blob: bca5dd4efade827ba91b9ee74547c8c8981b3ae5 [file] [log] [blame]
gogeralde069a452016-02-26 15:36:091// Copyright 2016 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 "device/bluetooth/bluetooth_remote_gatt_characteristic_win.h"
6
thakis08c9d69b02016-04-11 04:37:257#include <memory>
8
gogerald74459ac2016-03-01 20:45:369#include "base/bind.h"
thakis08c9d69b02016-04-11 04:37:2510#include "base/memory/ptr_util.h"
Giovanni Ortuño Urquidi36a75a162017-06-25 23:48:0111#include "base/threading/thread_task_runner_handle.h"
gogeralde069a452016-02-26 15:36:0912#include "device/bluetooth/bluetooth_adapter_win.h"
tommytad8462b2016-08-22 08:09:3913#include "device/bluetooth/bluetooth_gatt_notify_session.h"
gogerald74459ac2016-03-01 20:45:3614#include "device/bluetooth/bluetooth_remote_gatt_descriptor_win.h"
gogeralde069a452016-02-26 15:36:0915#include "device/bluetooth/bluetooth_remote_gatt_service_win.h"
16#include "device/bluetooth/bluetooth_task_manager_win.h"
17
18namespace device {
19
20BluetoothRemoteGattCharacteristicWin::BluetoothRemoteGattCharacteristicWin(
21 BluetoothRemoteGattServiceWin* parent_service,
22 BTH_LE_GATT_CHARACTERISTIC* characteristic_info,
23 scoped_refptr<base::SequencedTaskRunner>& ui_task_runner)
24 : parent_service_(parent_service),
25 characteristic_info_(characteristic_info),
26 ui_task_runner_(ui_task_runner),
gogerald74459ac2016-03-01 20:45:3627 characteristic_added_notified_(false),
gogerald50818ce52016-03-03 21:55:4828 characteristic_value_read_or_write_in_progress_(false),
gogerald08539da2016-04-08 18:51:4929 gatt_event_handle_(nullptr),
Conley Owens2f3d6fd32017-11-18 02:00:0430 discovery_pending_count_(0),
gogeralde069a452016-02-26 15:36:0931 weak_ptr_factory_(this) {
peary20bd3d49f2017-05-19 10:09:4132 DCHECK(ui_task_runner_->RunsTasksInCurrentSequence());
gogeralde069a452016-02-26 15:36:0933 DCHECK(parent_service_);
34 DCHECK(characteristic_info_);
35
gogerald74459ac2016-03-01 20:45:3636 task_manager_ =
37 parent_service_->GetWinAdapter()->GetWinBluetoothTaskManager();
gogeralde069a452016-02-26 15:36:0938 DCHECK(task_manager_);
gogerald74459ac2016-03-01 20:45:3639 characteristic_uuid_ =
40 BluetoothTaskManagerWin::BluetoothLowEnergyUuidToBluetoothUuid(
41 characteristic_info_->CharacteristicUuid);
gogeralde069a452016-02-26 15:36:0942 characteristic_identifier_ =
gogerald74459ac2016-03-01 20:45:3643 parent_service_->GetIdentifier() + "_" +
gogeralde069a452016-02-26 15:36:0944 std::to_string(characteristic_info_->AttributeHandle);
45 Update();
46}
47
48BluetoothRemoteGattCharacteristicWin::~BluetoothRemoteGattCharacteristicWin() {
peary20bd3d49f2017-05-19 10:09:4149 DCHECK(ui_task_runner_->RunsTasksInCurrentSequence());
gogeralde069a452016-02-26 15:36:0950
gogerald08539da2016-04-08 18:51:4951 ClearIncludedDescriptors();
52
53 if (gatt_event_handle_ != nullptr) {
54 task_manager_->PostUnregisterGattCharacteristicValueChangedEvent(
55 gatt_event_handle_);
56 gatt_event_handle_ = nullptr;
57 }
gogerald74459ac2016-03-01 20:45:3658 parent_service_->GetWinAdapter()->NotifyGattCharacteristicRemoved(this);
gogerald08539da2016-04-08 18:51:4959
ortuno650a52d2016-11-08 01:36:3060 if (!read_characteristic_value_callbacks_.first.is_null()) {
61 DCHECK(!read_characteristic_value_callbacks_.second.is_null());
62 read_characteristic_value_callbacks_.second.Run(
63 BluetoothRemoteGattService::GATT_ERROR_FAILED);
64 }
65
66 if (!write_characteristic_value_callbacks_.first.is_null()) {
67 DCHECK(!write_characteristic_value_callbacks_.second.is_null());
68 write_characteristic_value_callbacks_.second.Run(
69 BluetoothRemoteGattService::GATT_ERROR_FAILED);
70 }
71
gogerald08539da2016-04-08 18:51:4972 // Clear pending StartNotifySession callbacks.
73 for (const auto& callback : start_notify_session_callbacks_)
rkc122239752016-04-20 23:59:0874 callback.second.Run(BluetoothRemoteGattService::GATT_ERROR_FAILED);
gogeralde069a452016-02-26 15:36:0975}
76
77std::string BluetoothRemoteGattCharacteristicWin::GetIdentifier() const {
78 return characteristic_identifier_;
79}
80
81BluetoothUUID BluetoothRemoteGattCharacteristicWin::GetUUID() const {
82 return characteristic_uuid_;
83}
84
gogeralde069a452016-02-26 15:36:0985std::vector<uint8_t>& BluetoothRemoteGattCharacteristicWin::GetValue() const {
gogeralde069a452016-02-26 15:36:0986 return const_cast<std::vector<uint8_t>&>(characteristic_value_);
87}
88
rkc122239752016-04-20 23:59:0889BluetoothRemoteGattService* BluetoothRemoteGattCharacteristicWin::GetService()
90 const {
gogeralde069a452016-02-26 15:36:0991 return parent_service_;
92}
93
rkc122239752016-04-20 23:59:0894BluetoothRemoteGattCharacteristic::Properties
gogeralde069a452016-02-26 15:36:0995BluetoothRemoteGattCharacteristicWin::GetProperties() const {
rkc122239752016-04-20 23:59:0896 BluetoothRemoteGattCharacteristic::Properties properties = PROPERTY_NONE;
gogeralde069a452016-02-26 15:36:0997
98 if (characteristic_info_->IsBroadcastable)
99 properties = properties | PROPERTY_BROADCAST;
100 if (characteristic_info_->IsReadable)
101 properties = properties | PROPERTY_READ;
102 if (characteristic_info_->IsWritableWithoutResponse)
103 properties = properties | PROPERTY_WRITE_WITHOUT_RESPONSE;
104 if (characteristic_info_->IsWritable)
105 properties = properties | PROPERTY_WRITE;
106 if (characteristic_info_->IsNotifiable)
107 properties = properties | PROPERTY_NOTIFY;
108 if (characteristic_info_->IsIndicatable)
109 properties = properties | PROPERTY_INDICATE;
110 if (characteristic_info_->IsSignedWritable)
111 properties = properties | PROPERTY_AUTHENTICATED_SIGNED_WRITES;
112 if (characteristic_info_->HasExtendedProperties)
113 properties = properties | PROPERTY_EXTENDED_PROPERTIES;
114
115 // TODO(crbug.com/589304): Information about PROPERTY_RELIABLE_WRITE and
116 // PROPERTY_WRITABLE_AUXILIARIES is not available in characteristic_info_
117 // (BTH_LE_GATT_CHARACTERISTIC).
118
119 return properties;
120}
121
rkc122239752016-04-20 23:59:08122BluetoothRemoteGattCharacteristic::Permissions
gogeralde069a452016-02-26 15:36:09123BluetoothRemoteGattCharacteristicWin::GetPermissions() const {
rkc122239752016-04-20 23:59:08124 BluetoothRemoteGattCharacteristic::Permissions permissions = PERMISSION_NONE;
gogeralde069a452016-02-26 15:36:09125
126 if (characteristic_info_->IsReadable)
127 permissions = permissions | PERMISSION_READ;
128 if (characteristic_info_->IsWritable)
129 permissions = permissions | PERMISSION_WRITE;
130
131 return permissions;
132}
133
134bool BluetoothRemoteGattCharacteristicWin::IsNotifying() const {
gogerald08539da2016-04-08 18:51:49135 return gatt_event_handle_ != nullptr;
gogeralde069a452016-02-26 15:36:09136}
137
rkc122239752016-04-20 23:59:08138std::vector<BluetoothRemoteGattDescriptor*>
gogeralde069a452016-02-26 15:36:09139BluetoothRemoteGattCharacteristicWin::GetDescriptors() const {
rkc122239752016-04-20 23:59:08140 std::vector<BluetoothRemoteGattDescriptor*> descriptors;
gogerald74459ac2016-03-01 20:45:36141 for (const auto& descriptor : included_descriptors_)
142 descriptors.push_back(descriptor.second.get());
143 return descriptors;
gogeralde069a452016-02-26 15:36:09144}
145
rkc122239752016-04-20 23:59:08146BluetoothRemoteGattDescriptor*
147BluetoothRemoteGattCharacteristicWin::GetDescriptor(
gogeralde069a452016-02-26 15:36:09148 const std::string& identifier) const {
gogerald74459ac2016-03-01 20:45:36149 GattDescriptorMap::const_iterator it = included_descriptors_.find(identifier);
150 if (it != included_descriptors_.end())
151 return it->second.get();
gogeralde069a452016-02-26 15:36:09152 return nullptr;
153}
154
gogeralde069a452016-02-26 15:36:09155void BluetoothRemoteGattCharacteristicWin::ReadRemoteCharacteristic(
156 const ValueCallback& callback,
157 const ErrorCallback& error_callback) {
peary20bd3d49f2017-05-19 10:09:41158 DCHECK(ui_task_runner_->RunsTasksInCurrentSequence());
gogerald50818ce52016-03-03 21:55:48159
160 if (!characteristic_info_.get()->IsReadable) {
rkc122239752016-04-20 23:59:08161 error_callback.Run(BluetoothRemoteGattService::GATT_ERROR_NOT_PERMITTED);
gogerald50818ce52016-03-03 21:55:48162 return;
163 }
164
165 if (characteristic_value_read_or_write_in_progress_) {
rkc122239752016-04-20 23:59:08166 error_callback.Run(BluetoothRemoteGattService::GATT_ERROR_IN_PROGRESS);
gogerald50818ce52016-03-03 21:55:48167 return;
168 }
169
170 characteristic_value_read_or_write_in_progress_ = true;
171 read_characteristic_value_callbacks_ =
172 std::make_pair(callback, error_callback);
173 task_manager_->PostReadGattCharacteristicValue(
174 parent_service_->GetServicePath(), characteristic_info_.get(),
175 base::Bind(&BluetoothRemoteGattCharacteristicWin::
176 OnReadRemoteCharacteristicValueCallback,
177 weak_ptr_factory_.GetWeakPtr()));
gogeralde069a452016-02-26 15:36:09178}
179
180void BluetoothRemoteGattCharacteristicWin::WriteRemoteCharacteristic(
tommyt73e0d4d2016-09-01 20:06:24181 const std::vector<uint8_t>& value,
gogeralde069a452016-02-26 15:36:09182 const base::Closure& callback,
183 const ErrorCallback& error_callback) {
peary20bd3d49f2017-05-19 10:09:41184 DCHECK(ui_task_runner_->RunsTasksInCurrentSequence());
gogerald50818ce52016-03-03 21:55:48185
Conley Owensdce81a62017-11-22 21:08:13186 if (!characteristic_info_->IsWritable &&
187 !characteristic_info_->IsWritableWithoutResponse) {
rkc122239752016-04-20 23:59:08188 error_callback.Run(BluetoothRemoteGattService::GATT_ERROR_NOT_PERMITTED);
gogerald50818ce52016-03-03 21:55:48189 return;
190 }
191
192 if (characteristic_value_read_or_write_in_progress_) {
rkc122239752016-04-20 23:59:08193 error_callback.Run(BluetoothRemoteGattService::GATT_ERROR_IN_PROGRESS);
gogerald50818ce52016-03-03 21:55:48194 return;
195 }
196
197 characteristic_value_read_or_write_in_progress_ = true;
198 write_characteristic_value_callbacks_ =
199 std::make_pair(callback, error_callback);
200 task_manager_->PostWriteGattCharacteristicValue(
tommyt73e0d4d2016-09-01 20:06:24201 parent_service_->GetServicePath(), characteristic_info_.get(), value,
gogerald50818ce52016-03-03 21:55:48202 base::Bind(&BluetoothRemoteGattCharacteristicWin::
203 OnWriteRemoteCharacteristicValueCallback,
204 weak_ptr_factory_.GetWeakPtr()));
gogeralde069a452016-02-26 15:36:09205}
206
207void BluetoothRemoteGattCharacteristicWin::Update() {
peary20bd3d49f2017-05-19 10:09:41208 DCHECK(ui_task_runner_->RunsTasksInCurrentSequence());
gogerald74459ac2016-03-01 20:45:36209
Conley Owens2f3d6fd32017-11-18 02:00:04210 ++discovery_pending_count_;
gogerald74459ac2016-03-01 20:45:36211 task_manager_->PostGetGattIncludedDescriptors(
212 parent_service_->GetServicePath(), characteristic_info_.get(),
213 base::Bind(&BluetoothRemoteGattCharacteristicWin::
214 OnGetIncludedDescriptorsCallback,
215 weak_ptr_factory_.GetWeakPtr()));
gogeralde069a452016-02-26 15:36:09216}
217
218uint16_t BluetoothRemoteGattCharacteristicWin::GetAttributeHandle() const {
219 return characteristic_info_->AttributeHandle;
220}
221
tommytad8462b2016-08-22 08:09:39222void BluetoothRemoteGattCharacteristicWin::SubscribeToNotifications(
223 BluetoothRemoteGattDescriptor* ccc_descriptor,
224 const base::Closure& callback,
225 const ErrorCallback& error_callback) {
Giovanni Ortuño Urquidi36a75a162017-06-25 23:48:01226 task_manager_->PostRegisterGattCharacteristicValueChangedEvent(
227 parent_service_->GetServicePath(), characteristic_info_.get(),
228 static_cast<BluetoothRemoteGattDescriptorWin*>(ccc_descriptor)
229 ->GetWinDescriptorInfo(),
230 base::Bind(
231 &BluetoothRemoteGattCharacteristicWin::GattEventRegistrationCallback,
232 weak_ptr_factory_.GetWeakPtr(), callback, error_callback),
233 base::Bind(&BluetoothRemoteGattCharacteristicWin::
234 OnGattCharacteristicValueChanged,
235 weak_ptr_factory_.GetWeakPtr()));
tommytad8462b2016-08-22 08:09:39236}
237
238void BluetoothRemoteGattCharacteristicWin::UnsubscribeFromNotifications(
239 BluetoothRemoteGattDescriptor* ccc_descriptor,
240 const base::Closure& callback,
241 const ErrorCallback& error_callback) {
Giovanni Ortuño Urquidi36a75a162017-06-25 23:48:01242 // TODO(crbug.com/735828): Implement this method.
243 base::ThreadTaskRunnerHandle::Get()->PostTask(FROM_HERE, callback);
tommytad8462b2016-08-22 08:09:39244}
245
gogerald74459ac2016-03-01 20:45:36246void BluetoothRemoteGattCharacteristicWin::OnGetIncludedDescriptorsCallback(
thakis08c9d69b02016-04-11 04:37:25247 std::unique_ptr<BTH_LE_GATT_DESCRIPTOR> descriptors,
gogerald74459ac2016-03-01 20:45:36248 uint16_t num,
249 HRESULT hr) {
peary20bd3d49f2017-05-19 10:09:41250 DCHECK(ui_task_runner_->RunsTasksInCurrentSequence());
gogerald74459ac2016-03-01 20:45:36251
252 UpdateIncludedDescriptors(descriptors.get(), num);
253 if (!characteristic_added_notified_) {
254 characteristic_added_notified_ = true;
255 parent_service_->GetWinAdapter()->NotifyGattCharacteristicAdded(this);
256 }
Conley Owens2f3d6fd32017-11-18 02:00:04257
258 // Report discovery complete.
259 if (--discovery_pending_count_ == 0)
260 parent_service_->GattCharacteristicDiscoveryComplete(this);
gogerald74459ac2016-03-01 20:45:36261}
262
263void BluetoothRemoteGattCharacteristicWin::UpdateIncludedDescriptors(
264 PBTH_LE_GATT_DESCRIPTOR descriptors,
265 uint16_t num) {
266 if (num == 0) {
267 included_descriptors_.clear();
268 return;
269 }
270
271 // First, remove descriptors that no longer exist.
272 std::vector<std::string> to_be_removed;
273 for (const auto& d : included_descriptors_) {
274 if (!DoesDescriptorExist(descriptors, num, d.second.get()))
275 to_be_removed.push_back(d.second->GetIdentifier());
276 }
gogerald08539da2016-04-08 18:51:49277 for (auto id : to_be_removed) {
278 included_descriptors_[id].reset();
gogerald74459ac2016-03-01 20:45:36279 included_descriptors_.erase(id);
gogerald08539da2016-04-08 18:51:49280 }
gogerald74459ac2016-03-01 20:45:36281
282 // Return if no new descriptors have been added.
283 if (included_descriptors_.size() == num)
284 return;
285
286 // Add new descriptors.
287 for (uint16_t i = 0; i < num; i++) {
288 if (!IsDescriptorDiscovered(descriptors[i].DescriptorUuid,
289 descriptors[i].AttributeHandle)) {
290 PBTH_LE_GATT_DESCRIPTOR win_descriptor_info =
291 new BTH_LE_GATT_DESCRIPTOR();
292 *win_descriptor_info = descriptors[i];
293 BluetoothRemoteGattDescriptorWin* descriptor =
294 new BluetoothRemoteGattDescriptorWin(this, win_descriptor_info,
295 ui_task_runner_);
296 included_descriptors_[descriptor->GetIdentifier()] =
thakis08c9d69b02016-04-11 04:37:25297 base::WrapUnique(descriptor);
gogerald74459ac2016-03-01 20:45:36298 }
299 }
300}
301
302bool BluetoothRemoteGattCharacteristicWin::IsDescriptorDiscovered(
303 BTH_LE_UUID& uuid,
304 uint16_t attribute_handle) {
305 BluetoothUUID bt_uuid =
306 BluetoothTaskManagerWin::BluetoothLowEnergyUuidToBluetoothUuid(uuid);
307 for (const auto& d : included_descriptors_) {
308 if (bt_uuid == d.second->GetUUID() &&
309 attribute_handle == d.second->GetAttributeHandle()) {
310 return true;
311 }
312 }
313 return false;
314}
315
316bool BluetoothRemoteGattCharacteristicWin::DoesDescriptorExist(
317 PBTH_LE_GATT_DESCRIPTOR descriptors,
318 uint16_t num,
319 BluetoothRemoteGattDescriptorWin* descriptor) {
320 for (uint16_t i = 0; i < num; i++) {
321 BluetoothUUID uuid =
322 BluetoothTaskManagerWin::BluetoothLowEnergyUuidToBluetoothUuid(
323 descriptors[i].DescriptorUuid);
324 if (descriptor->GetUUID() == uuid &&
325 descriptor->GetAttributeHandle() == descriptors[i].AttributeHandle) {
326 return true;
327 }
328 }
329 return false;
330}
331
gogerald50818ce52016-03-03 21:55:48332void BluetoothRemoteGattCharacteristicWin::
333 OnReadRemoteCharacteristicValueCallback(
thakis08c9d69b02016-04-11 04:37:25334 std::unique_ptr<BTH_LE_GATT_CHARACTERISTIC_VALUE> value,
gogerald50818ce52016-03-03 21:55:48335 HRESULT hr) {
peary20bd3d49f2017-05-19 10:09:41336 DCHECK(ui_task_runner_->RunsTasksInCurrentSequence());
jdoerriecad402e32018-01-17 13:55:17337 characteristic_value_read_or_write_in_progress_ = false;
gogerald50818ce52016-03-03 21:55:48338
339 std::pair<ValueCallback, ErrorCallback> callbacks;
340 callbacks.swap(read_characteristic_value_callbacks_);
341 if (FAILED(hr)) {
342 callbacks.second.Run(HRESULTToGattErrorCode(hr));
343 } else {
344 characteristic_value_.clear();
345 for (ULONG i = 0; i < value->DataSize; i++)
346 characteristic_value_.push_back(value->Data[i]);
ortuno32321de2016-06-24 18:35:31347
gogerald50818ce52016-03-03 21:55:48348 callbacks.first.Run(characteristic_value_);
349 }
gogerald50818ce52016-03-03 21:55:48350}
351
352void BluetoothRemoteGattCharacteristicWin::
353 OnWriteRemoteCharacteristicValueCallback(HRESULT hr) {
peary20bd3d49f2017-05-19 10:09:41354 DCHECK(ui_task_runner_->RunsTasksInCurrentSequence());
jdoerriecad402e32018-01-17 13:55:17355 characteristic_value_read_or_write_in_progress_ = false;
gogerald50818ce52016-03-03 21:55:48356
357 std::pair<base::Closure, ErrorCallback> callbacks;
358 callbacks.swap(write_characteristic_value_callbacks_);
359 if (FAILED(hr)) {
360 callbacks.second.Run(HRESULTToGattErrorCode(hr));
361 } else {
362 callbacks.first.Run();
363 }
gogerald50818ce52016-03-03 21:55:48364}
365
rkc122239752016-04-20 23:59:08366BluetoothRemoteGattService::GattErrorCode
gogerald50818ce52016-03-03 21:55:48367BluetoothRemoteGattCharacteristicWin::HRESULTToGattErrorCode(HRESULT hr) {
gogerald08539da2016-04-08 18:51:49368 if (HRESULT_FROM_WIN32(ERROR_INVALID_USER_BUFFER) == hr)
rkc122239752016-04-20 23:59:08369 return BluetoothRemoteGattService::GATT_ERROR_INVALID_LENGTH;
gogerald08539da2016-04-08 18:51:49370
gogerald50818ce52016-03-03 21:55:48371 switch (hr) {
372 case E_BLUETOOTH_ATT_READ_NOT_PERMITTED:
373 case E_BLUETOOTH_ATT_WRITE_NOT_PERMITTED:
rkc122239752016-04-20 23:59:08374 return BluetoothRemoteGattService::GATT_ERROR_NOT_PERMITTED;
gogerald50818ce52016-03-03 21:55:48375 case E_BLUETOOTH_ATT_UNKNOWN_ERROR:
rkc122239752016-04-20 23:59:08376 return BluetoothRemoteGattService::GATT_ERROR_UNKNOWN;
gogerald50818ce52016-03-03 21:55:48377 case E_BLUETOOTH_ATT_INVALID_ATTRIBUTE_VALUE_LENGTH:
rkc122239752016-04-20 23:59:08378 return BluetoothRemoteGattService::GATT_ERROR_INVALID_LENGTH;
gogerald08539da2016-04-08 18:51:49379 case E_BLUETOOTH_ATT_REQUEST_NOT_SUPPORTED:
rkc122239752016-04-20 23:59:08380 return BluetoothRemoteGattService::GATT_ERROR_NOT_SUPPORTED;
gogerald50818ce52016-03-03 21:55:48381 default:
rkc122239752016-04-20 23:59:08382 return BluetoothRemoteGattService::GATT_ERROR_FAILED;
gogerald50818ce52016-03-03 21:55:48383 }
384}
385
gogerald08539da2016-04-08 18:51:49386void BluetoothRemoteGattCharacteristicWin::OnGattCharacteristicValueChanged(
thakis08c9d69b02016-04-11 04:37:25387 std::unique_ptr<std::vector<uint8_t>> new_value) {
peary20bd3d49f2017-05-19 10:09:41388 DCHECK(ui_task_runner_->RunsTasksInCurrentSequence());
gogerald08539da2016-04-08 18:51:49389
390 characteristic_value_.assign(new_value->begin(), new_value->end());
391 parent_service_->GetWinAdapter()->NotifyGattCharacteristicValueChanged(
392 this, characteristic_value_);
393}
394
395void BluetoothRemoteGattCharacteristicWin::GattEventRegistrationCallback(
Giovanni Ortuño Urquidi36a75a162017-06-25 23:48:01396 const base::Closure& callback,
397 const ErrorCallback& error_callback,
gogerald08539da2016-04-08 18:51:49398 BLUETOOTH_GATT_EVENT_HANDLE event_handle,
399 HRESULT hr) {
peary20bd3d49f2017-05-19 10:09:41400 DCHECK(ui_task_runner_->RunsTasksInCurrentSequence());
gogerald08539da2016-04-08 18:51:49401 if (SUCCEEDED(hr)) {
402 gatt_event_handle_ = event_handle;
Giovanni Ortuño Urquidi36a75a162017-06-25 23:48:01403 callback.Run();
gogerald08539da2016-04-08 18:51:49404 } else {
Giovanni Ortuño Urquidi36a75a162017-06-25 23:48:01405 error_callback.Run(HRESULTToGattErrorCode(hr));
gogerald08539da2016-04-08 18:51:49406 }
407}
408
409void BluetoothRemoteGattCharacteristicWin::ClearIncludedDescriptors() {
410 // Explicitly reset to null to ensure that calling GetDescriptor() on the
411 // removed descriptor in GattDescriptorRemoved() returns null.
412 for (auto& entry : included_descriptors_)
413 entry.second.reset();
414 included_descriptors_.clear();
415}
416
gogeralde069a452016-02-26 15:36:09417} // namespace device.