1 // 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 <utility>
6 #include <vector>
7
8 #include "base/bind.h"
9 #include "base/callback_helpers.h"
10 #include "base/memory/ptr_util.h"
11 #include "base/strings/utf_string_conversions.h"
12 #include "device/bluetooth/device.h"
13 #include "device/bluetooth/public/mojom/gatt_result_type_converter.h"
14 #include "mojo/public/cpp/bindings/self_owned_receiver.h"
15
16 namespace bluetooth {
~Device()17 Device::~Device() {
18 adapter_->RemoveObserver(this);
19 }
20
21 // static
Create(scoped_refptr<device::BluetoothAdapter> adapter,std::unique_ptr<device::BluetoothGattConnection> connection,mojo::PendingReceiver<mojom::Device> receiver)22 void Device::Create(scoped_refptr<device::BluetoothAdapter> adapter,
23 std::unique_ptr<device::BluetoothGattConnection> connection,
24 mojo::PendingReceiver<mojom::Device> receiver) {
25 auto device_impl =
26 base::WrapUnique(new Device(adapter, std::move(connection)));
27 auto* device_ptr = device_impl.get();
28 device_ptr->receiver_ =
29 mojo::MakeSelfOwnedReceiver(std::move(device_impl), std::move(receiver));
30 }
31
32 // static
ConstructDeviceInfoStruct(const device::BluetoothDevice * device)33 mojom::DeviceInfoPtr Device::ConstructDeviceInfoStruct(
34 const device::BluetoothDevice* device) {
35 mojom::DeviceInfoPtr device_info = mojom::DeviceInfo::New();
36
37 device_info->name = device->GetName();
38 device_info->name_for_display =
39 base::UTF16ToUTF8(device->GetNameForDisplay());
40 device_info->address = device->GetAddress();
41 device_info->is_gatt_connected = device->IsGattConnected();
42
43 if (device->GetInquiryRSSI()) {
44 device_info->rssi = mojom::RSSIWrapper::New();
45 device_info->rssi->value = device->GetInquiryRSSI().value();
46 }
47
48 for (auto const& it : device->GetServiceData())
49 device_info->service_data_map.insert_or_assign(it.first, it.second);
50
51 return device_info;
52 }
53
DeviceChanged(device::BluetoothAdapter * adapter,device::BluetoothDevice * device)54 void Device::DeviceChanged(device::BluetoothAdapter* adapter,
55 device::BluetoothDevice* device) {
56 if (device->GetAddress() != GetAddress()) {
57 return;
58 }
59
60 if (!device->IsGattConnected()) {
61 receiver_->Close();
62 }
63 }
64
GattServicesDiscovered(device::BluetoothAdapter * adapter,device::BluetoothDevice * device)65 void Device::GattServicesDiscovered(device::BluetoothAdapter* adapter,
66 device::BluetoothDevice* device) {
67 if (device->GetAddress() != GetAddress()) {
68 return;
69 }
70
71 std::vector<base::OnceClosure> requests;
72 requests.swap(pending_services_requests_);
73 for (base::OnceClosure& request : requests) {
74 std::move(request).Run();
75 }
76 }
77
Disconnect()78 void Device::Disconnect() {
79 receiver_->Close();
80 }
81
GetInfo(GetInfoCallback callback)82 void Device::GetInfo(GetInfoCallback callback) {
83 device::BluetoothDevice* device = adapter_->GetDevice(GetAddress());
84 DCHECK(device);
85
86 std::move(callback).Run(ConstructDeviceInfoStruct(device));
87 }
88
GetServices(GetServicesCallback callback)89 void Device::GetServices(GetServicesCallback callback) {
90 device::BluetoothDevice* device = adapter_->GetDevice(GetAddress());
91 DCHECK(device);
92
93 if (device->IsGattServicesDiscoveryComplete()) {
94 GetServicesImpl(std::move(callback));
95 return;
96 }
97
98 // pending_services_requests_ is owned by Device, so base::Unretained is
99 // safe.
100 pending_services_requests_.push_back(base::BindOnce(
101 &Device::GetServicesImpl, base::Unretained(this), std::move(callback)));
102 }
103
GetCharacteristics(const std::string & service_id,GetCharacteristicsCallback callback)104 void Device::GetCharacteristics(const std::string& service_id,
105 GetCharacteristicsCallback callback) {
106 device::BluetoothDevice* device = adapter_->GetDevice(GetAddress());
107 DCHECK(device);
108
109 device::BluetoothRemoteGattService* service =
110 device->GetGattService(service_id);
111 if (service == nullptr) {
112 std::move(callback).Run(base::nullopt);
113 return;
114 }
115
116 std::vector<mojom::CharacteristicInfoPtr> characteristics;
117
118 for (const auto* characteristic : service->GetCharacteristics()) {
119 mojom::CharacteristicInfoPtr characteristic_info =
120 mojom::CharacteristicInfo::New();
121
122 characteristic_info->id = characteristic->GetIdentifier();
123 characteristic_info->uuid = characteristic->GetUUID();
124 characteristic_info->properties = characteristic->GetProperties();
125
126 characteristics.push_back(std::move(characteristic_info));
127 }
128
129 std::move(callback).Run(std::move(characteristics));
130 }
131
ReadValueForCharacteristic(const std::string & service_id,const std::string & characteristic_id,ReadValueForCharacteristicCallback callback)132 void Device::ReadValueForCharacteristic(
133 const std::string& service_id,
134 const std::string& characteristic_id,
135 ReadValueForCharacteristicCallback callback) {
136 device::BluetoothDevice* device = adapter_->GetDevice(GetAddress());
137 DCHECK(device);
138
139 device::BluetoothRemoteGattService* service =
140 device->GetGattService(service_id);
141 if (service == nullptr) {
142 std::move(callback).Run(mojom::GattResult::SERVICE_NOT_FOUND,
143 base::nullopt /* value */);
144 return;
145 }
146
147 device::BluetoothRemoteGattCharacteristic* characteristic =
148 service->GetCharacteristic(characteristic_id);
149 if (characteristic == nullptr) {
150 std::move(callback).Run(mojom::GattResult::CHARACTERISTIC_NOT_FOUND,
151 base::nullopt /* value */);
152 return;
153 }
154
155 auto copyable_callback = base::AdaptCallbackForRepeating(std::move(callback));
156 characteristic->ReadRemoteCharacteristic(
157 base::BindOnce(&Device::OnReadRemoteCharacteristic,
158 weak_ptr_factory_.GetWeakPtr(), copyable_callback),
159 base::BindOnce(&Device::OnReadRemoteCharacteristicError,
160 weak_ptr_factory_.GetWeakPtr(), copyable_callback));
161 }
162
WriteValueForCharacteristic(const std::string & service_id,const std::string & characteristic_id,const std::vector<uint8_t> & value,WriteValueForCharacteristicCallback callback)163 void Device::WriteValueForCharacteristic(
164 const std::string& service_id,
165 const std::string& characteristic_id,
166 const std::vector<uint8_t>& value,
167 WriteValueForCharacteristicCallback callback) {
168 device::BluetoothDevice* device = adapter_->GetDevice(GetAddress());
169 DCHECK(device);
170
171 device::BluetoothRemoteGattService* service =
172 device->GetGattService(service_id);
173 if (service == nullptr) {
174 std::move(callback).Run(mojom::GattResult::SERVICE_NOT_FOUND);
175 return;
176 }
177
178 device::BluetoothRemoteGattCharacteristic* characteristic =
179 service->GetCharacteristic(characteristic_id);
180 if (characteristic == nullptr) {
181 std::move(callback).Run(mojom::GattResult::CHARACTERISTIC_NOT_FOUND);
182 return;
183 }
184
185 auto copyable_callback = base::AdaptCallbackForRepeating(std::move(callback));
186 characteristic->DeprecatedWriteRemoteCharacteristic(
187 value,
188 base::BindOnce(&Device::OnWriteRemoteCharacteristic,
189 weak_ptr_factory_.GetWeakPtr(), copyable_callback),
190 base::BindOnce(&Device::OnWriteRemoteCharacteristicError,
191 weak_ptr_factory_.GetWeakPtr(), copyable_callback));
192 }
193
GetDescriptors(const std::string & service_id,const std::string & characteristic_id,GetDescriptorsCallback callback)194 void Device::GetDescriptors(const std::string& service_id,
195 const std::string& characteristic_id,
196 GetDescriptorsCallback callback) {
197 device::BluetoothDevice* device = adapter_->GetDevice(GetAddress());
198 if (!device) {
199 std::move(callback).Run(base::nullopt);
200 return;
201 }
202
203 device::BluetoothRemoteGattService* service =
204 device->GetGattService(service_id);
205 if (!service) {
206 std::move(callback).Run(base::nullopt);
207 return;
208 }
209
210 device::BluetoothRemoteGattCharacteristic* characteristic =
211 service->GetCharacteristic(characteristic_id);
212 if (!characteristic) {
213 std::move(callback).Run(base::nullopt);
214 return;
215 }
216
217 std::vector<mojom::DescriptorInfoPtr> descriptors;
218
219 for (const auto* descriptor : characteristic->GetDescriptors()) {
220 mojom::DescriptorInfoPtr descriptor_info = mojom::DescriptorInfo::New();
221
222 descriptor_info->id = descriptor->GetIdentifier();
223 descriptor_info->uuid = descriptor->GetUUID();
224 descriptor_info->last_known_value = descriptor->GetValue();
225
226 descriptors.push_back(std::move(descriptor_info));
227 }
228
229 std::move(callback).Run(std::move(descriptors));
230 }
231
ReadValueForDescriptor(const std::string & service_id,const std::string & characteristic_id,const std::string & descriptor_id,ReadValueForDescriptorCallback callback)232 void Device::ReadValueForDescriptor(const std::string& service_id,
233 const std::string& characteristic_id,
234 const std::string& descriptor_id,
235 ReadValueForDescriptorCallback callback) {
236 device::BluetoothDevice* device = adapter_->GetDevice(GetAddress());
237 DCHECK(device);
238
239 device::BluetoothRemoteGattService* service =
240 device->GetGattService(service_id);
241 if (!service) {
242 std::move(callback).Run(mojom::GattResult::SERVICE_NOT_FOUND,
243 base::nullopt /* value */);
244 return;
245 }
246
247 device::BluetoothRemoteGattCharacteristic* characteristic =
248 service->GetCharacteristic(characteristic_id);
249 if (!characteristic) {
250 std::move(callback).Run(mojom::GattResult::CHARACTERISTIC_NOT_FOUND,
251 base::nullopt /* value */);
252 return;
253 }
254
255 device::BluetoothRemoteGattDescriptor* descriptor =
256 characteristic->GetDescriptor(descriptor_id);
257 if (!descriptor) {
258 std::move(callback).Run(mojom::GattResult::DESCRIPTOR_NOT_FOUND,
259 base::nullopt /* value */);
260 return;
261 }
262
263 auto copyable_callback = base::AdaptCallbackForRepeating(std::move(callback));
264 descriptor->ReadRemoteDescriptor(
265 base::BindOnce(&Device::OnReadRemoteDescriptor,
266 weak_ptr_factory_.GetWeakPtr(), copyable_callback),
267 base::BindOnce(&Device::OnReadRemoteDescriptorError,
268 weak_ptr_factory_.GetWeakPtr(), copyable_callback));
269 }
270
WriteValueForDescriptor(const std::string & service_id,const std::string & characteristic_id,const std::string & descriptor_id,const std::vector<uint8_t> & value,WriteValueForDescriptorCallback callback)271 void Device::WriteValueForDescriptor(const std::string& service_id,
272 const std::string& characteristic_id,
273 const std::string& descriptor_id,
274 const std::vector<uint8_t>& value,
275 WriteValueForDescriptorCallback callback) {
276 device::BluetoothDevice* device = adapter_->GetDevice(GetAddress());
277 DCHECK(device);
278
279 device::BluetoothRemoteGattService* service =
280 device->GetGattService(service_id);
281 if (!service) {
282 std::move(callback).Run(mojom::GattResult::SERVICE_NOT_FOUND);
283 return;
284 }
285
286 device::BluetoothRemoteGattCharacteristic* characteristic =
287 service->GetCharacteristic(characteristic_id);
288 if (!characteristic) {
289 std::move(callback).Run(mojom::GattResult::CHARACTERISTIC_NOT_FOUND);
290 return;
291 }
292
293 device::BluetoothRemoteGattDescriptor* descriptor =
294 characteristic->GetDescriptor(descriptor_id);
295 if (!descriptor) {
296 std::move(callback).Run(mojom::GattResult::DESCRIPTOR_NOT_FOUND);
297 return;
298 }
299
300 auto copyable_callback = base::AdaptCallbackForRepeating(std::move(callback));
301 descriptor->WriteRemoteDescriptor(
302 value,
303 base::BindOnce(&Device::OnWriteRemoteDescriptor,
304 weak_ptr_factory_.GetWeakPtr(), copyable_callback),
305 base::BindOnce(&Device::OnWriteRemoteDescriptorError,
306 weak_ptr_factory_.GetWeakPtr(), copyable_callback));
307 }
308
Device(scoped_refptr<device::BluetoothAdapter> adapter,std::unique_ptr<device::BluetoothGattConnection> connection)309 Device::Device(scoped_refptr<device::BluetoothAdapter> adapter,
310 std::unique_ptr<device::BluetoothGattConnection> connection)
311 : adapter_(std::move(adapter)), connection_(std::move(connection)) {
312 adapter_->AddObserver(this);
313 }
314
GetServicesImpl(GetServicesCallback callback)315 void Device::GetServicesImpl(GetServicesCallback callback) {
316 device::BluetoothDevice* device = adapter_->GetDevice(GetAddress());
317 DCHECK(device);
318
319 std::vector<mojom::ServiceInfoPtr> services;
320
321 for (const device::BluetoothRemoteGattService* service :
322 device->GetGattServices()) {
323 services.push_back(ConstructServiceInfoStruct(*service));
324 }
325
326 std::move(callback).Run(std::move(services));
327 }
328
ConstructServiceInfoStruct(const device::BluetoothRemoteGattService & service)329 mojom::ServiceInfoPtr Device::ConstructServiceInfoStruct(
330 const device::BluetoothRemoteGattService& service) {
331 mojom::ServiceInfoPtr service_info = mojom::ServiceInfo::New();
332
333 service_info->id = service.GetIdentifier();
334 service_info->uuid = service.GetUUID();
335 service_info->is_primary = service.IsPrimary();
336
337 return service_info;
338 }
339
OnReadRemoteCharacteristic(ReadValueForCharacteristicCallback callback,const std::vector<uint8_t> & value)340 void Device::OnReadRemoteCharacteristic(
341 ReadValueForCharacteristicCallback callback,
342 const std::vector<uint8_t>& value) {
343 std::move(callback).Run(mojom::GattResult::SUCCESS, std::move(value));
344 }
345
OnReadRemoteCharacteristicError(ReadValueForCharacteristicCallback callback,device::BluetoothGattService::GattErrorCode error_code)346 void Device::OnReadRemoteCharacteristicError(
347 ReadValueForCharacteristicCallback callback,
348 device::BluetoothGattService::GattErrorCode error_code) {
349 std::move(callback).Run(mojo::ConvertTo<mojom::GattResult>(error_code),
350 base::nullopt /* value */);
351 }
352
OnWriteRemoteCharacteristic(WriteValueForCharacteristicCallback callback)353 void Device::OnWriteRemoteCharacteristic(
354 WriteValueForCharacteristicCallback callback) {
355 std::move(callback).Run(mojom::GattResult::SUCCESS);
356 }
357
OnWriteRemoteCharacteristicError(WriteValueForCharacteristicCallback callback,device::BluetoothGattService::GattErrorCode error_code)358 void Device::OnWriteRemoteCharacteristicError(
359 WriteValueForCharacteristicCallback callback,
360 device::BluetoothGattService::GattErrorCode error_code) {
361 std::move(callback).Run(mojo::ConvertTo<mojom::GattResult>(error_code));
362 }
363
OnReadRemoteDescriptor(ReadValueForDescriptorCallback callback,const std::vector<uint8_t> & value)364 void Device::OnReadRemoteDescriptor(ReadValueForDescriptorCallback callback,
365 const std::vector<uint8_t>& value) {
366 std::move(callback).Run(mojom::GattResult::SUCCESS, std::move(value));
367 }
368
OnReadRemoteDescriptorError(ReadValueForDescriptorCallback callback,device::BluetoothGattService::GattErrorCode error_code)369 void Device::OnReadRemoteDescriptorError(
370 ReadValueForDescriptorCallback callback,
371 device::BluetoothGattService::GattErrorCode error_code) {
372 std::move(callback).Run(mojo::ConvertTo<mojom::GattResult>(error_code),
373 base::nullopt /* value */);
374 }
375
OnWriteRemoteDescriptor(WriteValueForDescriptorCallback callback)376 void Device::OnWriteRemoteDescriptor(WriteValueForDescriptorCallback callback) {
377 std::move(callback).Run(mojom::GattResult::SUCCESS);
378 }
379
OnWriteRemoteDescriptorError(WriteValueForDescriptorCallback callback,device::BluetoothGattService::GattErrorCode error_code)380 void Device::OnWriteRemoteDescriptorError(
381 WriteValueForDescriptorCallback callback,
382 device::BluetoothGattService::GattErrorCode error_code) {
383 std::move(callback).Run(mojo::ConvertTo<mojom::GattResult>(error_code));
384 }
385
GetAddress()386 const std::string& Device::GetAddress() {
387 return connection_->GetDeviceAddress();
388 }
389
390 } // namespace bluetooth
391