Move notification sending out of AutocompleteController
[chromium-blink-merge.git] / device / bluetooth / bluetooth_remote_gatt_characteristic_chromeos.cc
blob5be8c788c7be7b6b1dbbf2282ef9c549da04ebac
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.
5 #include "device/bluetooth/bluetooth_remote_gatt_characteristic_chromeos.h"
7 #include <limits>
9 #include "base/logging.h"
10 #include "base/strings/stringprintf.h"
11 #include "chromeos/dbus/dbus_thread_manager.h"
12 #include "device/bluetooth/bluetooth_adapter_chromeos.h"
13 #include "device/bluetooth/bluetooth_device.h"
14 #include "device/bluetooth/bluetooth_gatt_notify_session_chromeos.h"
15 #include "device/bluetooth/bluetooth_remote_gatt_characteristic_chromeos.h"
16 #include "device/bluetooth/bluetooth_remote_gatt_descriptor_chromeos.h"
17 #include "device/bluetooth/bluetooth_remote_gatt_service_chromeos.h"
18 #include "third_party/cros_system_api/dbus/service_constants.h"
20 namespace chromeos {
22 namespace {
24 // Stream operator for logging vector<uint8>.
25 std::ostream& operator<<(std::ostream& out, const std::vector<uint8> bytes) {
26 out << "[";
27 for (std::vector<uint8>::const_iterator iter = bytes.begin();
28 iter != bytes.end(); ++iter) {
29 out << base::StringPrintf("%02X", *iter);
31 return out << "]";
34 } // namespace
36 BluetoothRemoteGattCharacteristicChromeOS::
37 BluetoothRemoteGattCharacteristicChromeOS(
38 BluetoothRemoteGattServiceChromeOS* service,
39 const dbus::ObjectPath& object_path)
40 : object_path_(object_path),
41 service_(service),
42 num_notify_sessions_(0),
43 notify_call_pending_(false),
44 weak_ptr_factory_(this) {
45 VLOG(1) << "Creating remote GATT characteristic with identifier: "
46 << GetIdentifier() << ", UUID: " << GetUUID().canonical_value();
47 DBusThreadManager::Get()->GetBluetoothGattDescriptorClient()->
48 AddObserver(this);
50 // Add all known GATT characteristic descriptors.
51 const std::vector<dbus::ObjectPath>& gatt_descs =
52 DBusThreadManager::Get()->GetBluetoothGattDescriptorClient()->
53 GetDescriptors();
54 for (std::vector<dbus::ObjectPath>::const_iterator iter = gatt_descs.begin();
55 iter != gatt_descs.end(); ++iter)
56 GattDescriptorAdded(*iter);
59 BluetoothRemoteGattCharacteristicChromeOS::
60 ~BluetoothRemoteGattCharacteristicChromeOS() {
61 DBusThreadManager::Get()->GetBluetoothGattDescriptorClient()->
62 RemoveObserver(this);
64 // Clean up all the descriptors. There isn't much point in notifying service
65 // observers for each descriptor that gets removed, so just delete them.
66 for (DescriptorMap::iterator iter = descriptors_.begin();
67 iter != descriptors_.end(); ++iter)
68 delete iter->second;
70 // Report an error for all pending calls to StartNotifySession.
71 while (!pending_start_notify_calls_.empty()) {
72 PendingStartNotifyCall callbacks = pending_start_notify_calls_.front();
73 pending_start_notify_calls_.pop();
74 callbacks.second.Run(device::BluetoothGattService::GATT_ERROR_FAILED);
78 std::string BluetoothRemoteGattCharacteristicChromeOS::GetIdentifier() const {
79 return object_path_.value();
82 device::BluetoothUUID
83 BluetoothRemoteGattCharacteristicChromeOS::GetUUID() const {
84 BluetoothGattCharacteristicClient::Properties* properties =
85 DBusThreadManager::Get()->GetBluetoothGattCharacteristicClient()->
86 GetProperties(object_path_);
87 DCHECK(properties);
88 return device::BluetoothUUID(properties->uuid.value());
91 bool BluetoothRemoteGattCharacteristicChromeOS::IsLocal() const {
92 return false;
95 const std::vector<uint8>&
96 BluetoothRemoteGattCharacteristicChromeOS::GetValue() const {
97 BluetoothGattCharacteristicClient::Properties* properties =
98 DBusThreadManager::Get()
99 ->GetBluetoothGattCharacteristicClient()
100 ->GetProperties(object_path_);
102 DCHECK(properties);
104 return properties->value.value();
107 device::BluetoothGattService*
108 BluetoothRemoteGattCharacteristicChromeOS::GetService() const {
109 return service_;
112 device::BluetoothGattCharacteristic::Properties
113 BluetoothRemoteGattCharacteristicChromeOS::GetProperties() const {
114 BluetoothGattCharacteristicClient::Properties* properties =
115 DBusThreadManager::Get()->GetBluetoothGattCharacteristicClient()->
116 GetProperties(object_path_);
117 DCHECK(properties);
119 Properties props = PROPERTY_NONE;
120 const std::vector<std::string>& flags = properties->flags.value();
121 for (std::vector<std::string>::const_iterator iter = flags.begin();
122 iter != flags.end();
123 ++iter) {
124 if (*iter == bluetooth_gatt_characteristic::kFlagBroadcast)
125 props |= PROPERTY_BROADCAST;
126 if (*iter == bluetooth_gatt_characteristic::kFlagRead)
127 props |= PROPERTY_READ;
128 if (*iter == bluetooth_gatt_characteristic::kFlagWriteWithoutResponse)
129 props |= PROPERTY_WRITE_WITHOUT_RESPONSE;
130 if (*iter == bluetooth_gatt_characteristic::kFlagWrite)
131 props |= PROPERTY_WRITE;
132 if (*iter == bluetooth_gatt_characteristic::kFlagNotify)
133 props |= PROPERTY_NOTIFY;
134 if (*iter == bluetooth_gatt_characteristic::kFlagIndicate)
135 props |= PROPERTY_INDICATE;
136 if (*iter == bluetooth_gatt_characteristic::kFlagAuthenticatedSignedWrites)
137 props |= PROPERTY_AUTHENTICATED_SIGNED_WRITES;
138 if (*iter == bluetooth_gatt_characteristic::kFlagExtendedProperties)
139 props |= PROPERTY_EXTENDED_PROPERTIES;
140 if (*iter == bluetooth_gatt_characteristic::kFlagReliableWrite)
141 props |= PROPERTY_RELIABLE_WRITE;
142 if (*iter == bluetooth_gatt_characteristic::kFlagWritableAuxiliaries)
143 props |= PROPERTY_WRITABLE_AUXILIARIES;
146 return props;
149 device::BluetoothGattCharacteristic::Permissions
150 BluetoothRemoteGattCharacteristicChromeOS::GetPermissions() const {
151 // TODO(armansito): Once BlueZ defines the permissions, return the correct
152 // values here.
153 return PERMISSION_NONE;
156 bool BluetoothRemoteGattCharacteristicChromeOS::IsNotifying() const {
157 BluetoothGattCharacteristicClient::Properties* properties =
158 DBusThreadManager::Get()
159 ->GetBluetoothGattCharacteristicClient()
160 ->GetProperties(object_path_);
161 DCHECK(properties);
163 return properties->notifying.value();
166 std::vector<device::BluetoothGattDescriptor*>
167 BluetoothRemoteGattCharacteristicChromeOS::GetDescriptors() const {
168 std::vector<device::BluetoothGattDescriptor*> descriptors;
169 for (DescriptorMap::const_iterator iter = descriptors_.begin();
170 iter != descriptors_.end(); ++iter)
171 descriptors.push_back(iter->second);
172 return descriptors;
175 device::BluetoothGattDescriptor*
176 BluetoothRemoteGattCharacteristicChromeOS::GetDescriptor(
177 const std::string& identifier) const {
178 DescriptorMap::const_iterator iter =
179 descriptors_.find(dbus::ObjectPath(identifier));
180 if (iter == descriptors_.end())
181 return NULL;
182 return iter->second;
185 bool BluetoothRemoteGattCharacteristicChromeOS::AddDescriptor(
186 device::BluetoothGattDescriptor* descriptor) {
187 VLOG(1) << "Descriptors cannot be added to a remote GATT characteristic.";
188 return false;
191 bool BluetoothRemoteGattCharacteristicChromeOS::UpdateValue(
192 const std::vector<uint8>& value) {
193 VLOG(1) << "Cannot update the value of a remote GATT characteristic.";
194 return false;
197 void BluetoothRemoteGattCharacteristicChromeOS::ReadRemoteCharacteristic(
198 const ValueCallback& callback,
199 const ErrorCallback& error_callback) {
200 VLOG(1) << "Sending GATT characteristic read request to characteristic: "
201 << GetIdentifier() << ", UUID: " << GetUUID().canonical_value()
202 << ".";
204 DBusThreadManager::Get()->GetBluetoothGattCharacteristicClient()->ReadValue(
205 object_path_, callback,
206 base::Bind(&BluetoothRemoteGattCharacteristicChromeOS::OnError,
207 weak_ptr_factory_.GetWeakPtr(), error_callback));
210 void BluetoothRemoteGattCharacteristicChromeOS::WriteRemoteCharacteristic(
211 const std::vector<uint8>& new_value,
212 const base::Closure& callback,
213 const ErrorCallback& error_callback) {
214 VLOG(1) << "Sending GATT characteristic write request to characteristic: "
215 << GetIdentifier() << ", UUID: " << GetUUID().canonical_value()
216 << ", with value: " << new_value << ".";
218 DBusThreadManager::Get()->GetBluetoothGattCharacteristicClient()->WriteValue(
219 object_path_,
220 new_value,
221 callback,
222 base::Bind(&BluetoothRemoteGattCharacteristicChromeOS::OnError,
223 weak_ptr_factory_.GetWeakPtr(),
224 error_callback));
227 void BluetoothRemoteGattCharacteristicChromeOS::StartNotifySession(
228 const NotifySessionCallback& callback,
229 const ErrorCallback& error_callback) {
230 VLOG(1) << __func__;
232 if (num_notify_sessions_ > 0) {
233 // The characteristic might have stopped notifying even though the session
234 // count is nonzero. This means that notifications stopped outside of our
235 // control and we should reset the count. If the characteristic is still
236 // notifying, then return success. Otherwise, reset the count and treat
237 // this call as if the count were 0.
238 if (IsNotifying()) {
239 // Check for overflows, though unlikely.
240 if (num_notify_sessions_ == std::numeric_limits<size_t>::max()) {
241 error_callback.Run(device::BluetoothGattService::GATT_ERROR_FAILED);
242 return;
245 ++num_notify_sessions_;
246 DCHECK(service_);
247 DCHECK(service_->GetAdapter());
248 DCHECK(service_->GetDevice());
249 scoped_ptr<device::BluetoothGattNotifySession> session(
250 new BluetoothGattNotifySessionChromeOS(
251 service_->GetAdapter(),
252 service_->GetDevice()->GetAddress(),
253 service_->GetIdentifier(),
254 GetIdentifier(),
255 object_path_));
256 callback.Run(session.Pass());
257 return;
260 num_notify_sessions_ = 0;
263 // Queue the callbacks if there is a pending call to bluetoothd.
264 if (notify_call_pending_) {
265 pending_start_notify_calls_.push(std::make_pair(callback, error_callback));
266 return;
269 notify_call_pending_ = true;
270 DBusThreadManager::Get()->GetBluetoothGattCharacteristicClient()->StartNotify(
271 object_path_,
272 base::Bind(
273 &BluetoothRemoteGattCharacteristicChromeOS::OnStartNotifySuccess,
274 weak_ptr_factory_.GetWeakPtr(),
275 callback),
276 base::Bind(&BluetoothRemoteGattCharacteristicChromeOS::OnStartNotifyError,
277 weak_ptr_factory_.GetWeakPtr(),
278 error_callback));
281 void BluetoothRemoteGattCharacteristicChromeOS::RemoveNotifySession(
282 const base::Closure& callback) {
283 VLOG(1) << __func__;
285 if (num_notify_sessions_ > 1) {
286 DCHECK(!notify_call_pending_);
287 --num_notify_sessions_;
288 callback.Run();
289 return;
292 // Notifications may have stopped outside our control. If the characteristic
293 // is no longer notifying, return success.
294 if (!IsNotifying()) {
295 num_notify_sessions_ = 0;
296 callback.Run();
297 return;
300 if (notify_call_pending_ || num_notify_sessions_ == 0) {
301 callback.Run();
302 return;
305 DCHECK(num_notify_sessions_ == 1);
306 notify_call_pending_ = true;
307 DBusThreadManager::Get()->GetBluetoothGattCharacteristicClient()->StopNotify(
308 object_path_,
309 base::Bind(
310 &BluetoothRemoteGattCharacteristicChromeOS::OnStopNotifySuccess,
311 weak_ptr_factory_.GetWeakPtr(),
312 callback),
313 base::Bind(&BluetoothRemoteGattCharacteristicChromeOS::OnStopNotifyError,
314 weak_ptr_factory_.GetWeakPtr(),
315 callback));
318 void BluetoothRemoteGattCharacteristicChromeOS::GattDescriptorAdded(
319 const dbus::ObjectPath& object_path) {
320 if (descriptors_.find(object_path) != descriptors_.end()) {
321 VLOG(1) << "Remote GATT characteristic descriptor already exists: "
322 << object_path.value();
323 return;
326 BluetoothGattDescriptorClient::Properties* properties =
327 DBusThreadManager::Get()->GetBluetoothGattDescriptorClient()->
328 GetProperties(object_path);
329 DCHECK(properties);
330 if (properties->characteristic.value() != object_path_) {
331 VLOG(3) << "Remote GATT descriptor does not belong to this characteristic.";
332 return;
335 VLOG(1) << "Adding new remote GATT descriptor for GATT characteristic: "
336 << GetIdentifier() << ", UUID: " << GetUUID().canonical_value();
338 BluetoothRemoteGattDescriptorChromeOS* descriptor =
339 new BluetoothRemoteGattDescriptorChromeOS(this, object_path);
340 descriptors_[object_path] = descriptor;
341 DCHECK(descriptor->GetIdentifier() == object_path.value());
342 DCHECK(descriptor->GetUUID().IsValid());
343 DCHECK(service_);
345 service_->NotifyDescriptorAddedOrRemoved(this, descriptor, true /* added */);
348 void BluetoothRemoteGattCharacteristicChromeOS::GattDescriptorRemoved(
349 const dbus::ObjectPath& object_path) {
350 DescriptorMap::iterator iter = descriptors_.find(object_path);
351 if (iter == descriptors_.end()) {
352 VLOG(2) << "Unknown descriptor removed: " << object_path.value();
353 return;
356 VLOG(1) << "Removing remote GATT descriptor from characteristic: "
357 << GetIdentifier() << ", UUID: " << GetUUID().canonical_value();
359 BluetoothRemoteGattDescriptorChromeOS* descriptor = iter->second;
360 DCHECK(descriptor->object_path() == object_path);
361 descriptors_.erase(iter);
363 DCHECK(service_);
364 service_->NotifyDescriptorAddedOrRemoved(this, descriptor, false /* added */);
366 delete descriptor;
369 void BluetoothRemoteGattCharacteristicChromeOS::GattDescriptorPropertyChanged(
370 const dbus::ObjectPath& object_path,
371 const std::string& property_name) {
372 DescriptorMap::iterator iter = descriptors_.find(object_path);
373 if (iter == descriptors_.end()) {
374 VLOG(2) << "Unknown descriptor removed: " << object_path.value();
375 return;
378 BluetoothGattDescriptorClient::Properties* properties =
379 DBusThreadManager::Get()
380 ->GetBluetoothGattDescriptorClient()
381 ->GetProperties(object_path);
383 DCHECK(properties);
385 if (property_name != properties->value.name())
386 return;
388 DCHECK(service_);
389 service_->NotifyDescriptorValueChanged(this, iter->second,
390 properties->value.value());
393 void BluetoothRemoteGattCharacteristicChromeOS::OnError(
394 const ErrorCallback& error_callback,
395 const std::string& error_name,
396 const std::string& error_message) {
397 VLOG(1) << "Operation failed: " << error_name << ", message: "
398 << error_message;
399 error_callback.Run(
400 BluetoothRemoteGattServiceChromeOS::DBusErrorToServiceError(error_name));
403 void BluetoothRemoteGattCharacteristicChromeOS::OnStartNotifySuccess(
404 const NotifySessionCallback& callback) {
405 VLOG(1) << "Started notifications from characteristic: "
406 << object_path_.value();
407 DCHECK(num_notify_sessions_ == 0);
408 DCHECK(notify_call_pending_);
410 ++num_notify_sessions_;
411 notify_call_pending_ = false;
413 // Invoke the queued callbacks for this operation.
414 DCHECK(service_);
415 DCHECK(service_->GetDevice());
416 scoped_ptr<device::BluetoothGattNotifySession> session(
417 new BluetoothGattNotifySessionChromeOS(
418 service_->GetAdapter(),
419 service_->GetDevice()->GetAddress(),
420 service_->GetIdentifier(),
421 GetIdentifier(),
422 object_path_));
423 callback.Run(session.Pass());
425 ProcessStartNotifyQueue();
428 void BluetoothRemoteGattCharacteristicChromeOS::OnStartNotifyError(
429 const ErrorCallback& error_callback,
430 const std::string& error_name,
431 const std::string& error_message) {
432 VLOG(1) << "Failed to start notifications from characteristic: "
433 << object_path_.value() << ": " << error_name << ", "
434 << error_message;
435 DCHECK(num_notify_sessions_ == 0);
436 DCHECK(notify_call_pending_);
438 notify_call_pending_ = false;
440 error_callback.Run(
441 BluetoothRemoteGattServiceChromeOS::DBusErrorToServiceError(error_name));
443 ProcessStartNotifyQueue();
446 void BluetoothRemoteGattCharacteristicChromeOS::OnStopNotifySuccess(
447 const base::Closure& callback) {
448 DCHECK(notify_call_pending_);
449 DCHECK(num_notify_sessions_ == 1);
451 notify_call_pending_ = false;
452 --num_notify_sessions_;
453 callback.Run();
455 ProcessStartNotifyQueue();
458 void BluetoothRemoteGattCharacteristicChromeOS::OnStopNotifyError(
459 const base::Closure& callback,
460 const std::string& error_name,
461 const std::string& error_message) {
462 VLOG(1) << "Call to stop notifications failed for characteristic: "
463 << object_path_.value() << ": " << error_name << ", "
464 << error_message;
466 // Since this is a best effort operation, treat this as success.
467 OnStopNotifySuccess(callback);
470 void BluetoothRemoteGattCharacteristicChromeOS::ProcessStartNotifyQueue() {
471 while (!pending_start_notify_calls_.empty()) {
472 PendingStartNotifyCall callbacks = pending_start_notify_calls_.front();
473 pending_start_notify_calls_.pop();
474 StartNotifySession(callbacks.first, callbacks.second);
478 } // namespace chromeos