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