1 // Copyright 2018 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/cast/bluetooth_device_cast.h"
6 
7 #include <inttypes.h>
8 
9 #include <unordered_set>
10 #include <utility>
11 
12 #include "base/bind.h"
13 #include "base/strings/stringprintf.h"
14 #include "chromecast/device/bluetooth/bluetooth_util.h"
15 #include "chromecast/device/bluetooth/le/remote_characteristic.h"
16 #include "chromecast/device/bluetooth/le/remote_service.h"
17 #include "device/bluetooth/bluetooth_adapter.h"
18 #include "device/bluetooth/cast/bluetooth_remote_gatt_characteristic_cast.h"
19 #include "device/bluetooth/cast/bluetooth_remote_gatt_service_cast.h"
20 #include "device/bluetooth/cast/bluetooth_utils.h"
21 
22 namespace device {
23 namespace {
24 
ExtractServiceUuids(const chromecast::bluetooth::LeScanResult & result)25 BluetoothDevice::UUIDSet ExtractServiceUuids(
26     const chromecast::bluetooth::LeScanResult& result) {
27   BluetoothDevice::UUIDSet ret;
28   auto uuids = result.AllServiceUuids();
29   if (!uuids)
30     return ret;
31 
32   for (const auto& uuid : *uuids)
33     ret.insert(UuidToBluetoothUUID(uuid));
34   return ret;
35 }
36 
ExtractServiceData(const chromecast::bluetooth::LeScanResult & result)37 BluetoothDevice::ServiceDataMap ExtractServiceData(
38     const chromecast::bluetooth::LeScanResult& result) {
39   BluetoothDevice::ServiceDataMap service_data;
40   for (const auto& it : result.AllServiceData()) {
41     service_data.insert(
42         std::make_pair(UuidToBluetoothUUID(it.first), it.second));
43   }
44   return service_data;
45 }
46 
ExtractManufacturerData(const chromecast::bluetooth::LeScanResult & result)47 BluetoothDevice::ManufacturerDataMap ExtractManufacturerData(
48     const chromecast::bluetooth::LeScanResult& result) {
49   BluetoothDevice::ManufacturerDataMap ret;
50   for (const auto& it : result.ManufacturerData())
51     ret.insert(std::make_pair(it.first, it.second));
52   return ret;
53 }
54 
55 }  // namespace
56 
BluetoothDeviceCast(BluetoothAdapter * adapter,scoped_refptr<chromecast::bluetooth::RemoteDevice> device)57 BluetoothDeviceCast::BluetoothDeviceCast(
58     BluetoothAdapter* adapter,
59     scoped_refptr<chromecast::bluetooth::RemoteDevice> device)
60     : BluetoothDevice(adapter),
61       connected_(device->IsConnected()),
62       remote_device_(std::move(device)),
63       address_(GetCanonicalBluetoothAddress(remote_device_->addr())),
64       weak_factory_(this) {
65   if (connected_) {
66     remote_device_->GetServices(base::BindOnce(
67         &BluetoothDeviceCast::OnGetServices, weak_factory_.GetWeakPtr()));
68   }
69 }
70 
~BluetoothDeviceCast()71 BluetoothDeviceCast::~BluetoothDeviceCast() {}
72 
GetBluetoothClass() const73 uint32_t BluetoothDeviceCast::GetBluetoothClass() const {
74   // Return the code for miscellaneous device.
75   return 0x1F00;
76 }
77 
GetType() const78 BluetoothTransport BluetoothDeviceCast::GetType() const {
79   return BLUETOOTH_TRANSPORT_LE;
80 }
81 
GetAddress() const82 std::string BluetoothDeviceCast::GetAddress() const {
83   return address_;
84 }
85 
GetVendorIDSource() const86 BluetoothDevice::VendorIDSource BluetoothDeviceCast::GetVendorIDSource() const {
87   return VENDOR_ID_UNKNOWN;
88 }
89 
GetVendorID() const90 uint16_t BluetoothDeviceCast::GetVendorID() const {
91   return 0;
92 }
93 
GetProductID() const94 uint16_t BluetoothDeviceCast::GetProductID() const {
95   return 0;
96 }
97 
GetDeviceID() const98 uint16_t BluetoothDeviceCast::GetDeviceID() const {
99   return 0;
100 }
101 
GetAppearance() const102 uint16_t BluetoothDeviceCast::GetAppearance() const {
103   return 0;
104 }
105 
GetName() const106 base::Optional<std::string> BluetoothDeviceCast::GetName() const {
107   return name_;
108 }
109 
IsPaired() const110 bool BluetoothDeviceCast::IsPaired() const {
111   return false;
112 }
113 
IsConnected() const114 bool BluetoothDeviceCast::IsConnected() const {
115   return connected_;
116 }
117 
IsGattConnected() const118 bool BluetoothDeviceCast::IsGattConnected() const {
119   return IsConnected();
120 }
121 
IsConnectable() const122 bool BluetoothDeviceCast::IsConnectable() const {
123   NOTREACHED() << "This is only called on ChromeOS";
124   return true;
125 }
126 
IsConnecting() const127 bool BluetoothDeviceCast::IsConnecting() const {
128   return pending_connect_;
129 }
130 
GetInquiryRSSI() const131 base::Optional<int8_t> BluetoothDeviceCast::GetInquiryRSSI() const {
132   // TODO(slan): Plumb this from the type_to_data field of ScanResult.
133   return BluetoothDevice::GetInquiryRSSI();
134 }
135 
GetInquiryTxPower() const136 base::Optional<int8_t> BluetoothDeviceCast::GetInquiryTxPower() const {
137   // TODO(slan): Remove if we do not need this.
138   return BluetoothDevice::GetInquiryTxPower();
139 }
140 
ExpectingPinCode() const141 bool BluetoothDeviceCast::ExpectingPinCode() const {
142   // TODO(slan): Implement this or rely on lower layers to do so.
143   NOTIMPLEMENTED();
144   return false;
145 }
146 
ExpectingPasskey() const147 bool BluetoothDeviceCast::ExpectingPasskey() const {
148   NOTIMPLEMENTED() << "Only BLE functionality is supported.";
149   return false;
150 }
151 
ExpectingConfirmation() const152 bool BluetoothDeviceCast::ExpectingConfirmation() const {
153   NOTIMPLEMENTED() << "Only BLE functionality is supported.";
154   return false;
155 }
156 
GetConnectionInfo(const ConnectionInfoCallback & callback)157 void BluetoothDeviceCast::GetConnectionInfo(
158     const ConnectionInfoCallback& callback) {
159   // TODO(slan): Implement this?
160   NOTIMPLEMENTED();
161 }
162 
SetConnectionLatency(ConnectionLatency connection_latency,const base::Closure & callback,const ErrorCallback & error_callback)163 void BluetoothDeviceCast::SetConnectionLatency(
164     ConnectionLatency connection_latency,
165     const base::Closure& callback,
166     const ErrorCallback& error_callback) {
167   // TODO(slan): This many be needed for some high-performance BLE devices.
168   NOTIMPLEMENTED();
169   error_callback.Run();
170 }
171 
Connect(PairingDelegate * pairing_delegate,base::OnceClosure callback,ConnectErrorCallback error_callback)172 void BluetoothDeviceCast::Connect(PairingDelegate* pairing_delegate,
173                                   base::OnceClosure callback,
174                                   ConnectErrorCallback error_callback) {
175   // This method is used only for Bluetooth classic.
176   NOTIMPLEMENTED() << __func__ << " Only BLE functionality is supported.";
177   std::move(error_callback).Run(BluetoothDevice::ERROR_UNSUPPORTED_DEVICE);
178 }
179 
Pair(PairingDelegate * pairing_delegate,base::OnceClosure callback,ConnectErrorCallback error_callback)180 void BluetoothDeviceCast::Pair(PairingDelegate* pairing_delegate,
181                                base::OnceClosure callback,
182                                ConnectErrorCallback error_callback) {
183   // TODO(slan): Implement this or delegate to lower level.
184   NOTIMPLEMENTED();
185   std::move(error_callback).Run(BluetoothDevice::ERROR_UNSUPPORTED_DEVICE);
186 }
187 
SetPinCode(const std::string & pincode)188 void BluetoothDeviceCast::SetPinCode(const std::string& pincode) {
189   NOTREACHED() << "Pairing not supported.";
190 }
191 
SetPasskey(uint32_t passkey)192 void BluetoothDeviceCast::SetPasskey(uint32_t passkey) {
193   NOTREACHED() << "Pairing not supported.";
194 }
195 
ConfirmPairing()196 void BluetoothDeviceCast::ConfirmPairing() {
197   NOTREACHED() << "Pairing not supported.";
198 }
199 
200 // Rejects a pairing or connection request from a remote device.
RejectPairing()201 void BluetoothDeviceCast::RejectPairing() {
202   NOTREACHED() << "Pairing not supported.";
203 }
204 
CancelPairing()205 void BluetoothDeviceCast::CancelPairing() {
206   NOTREACHED() << "Pairing not supported.";
207 }
208 
Disconnect(const base::Closure & callback,const ErrorCallback & error_callback)209 void BluetoothDeviceCast::Disconnect(const base::Closure& callback,
210                                      const ErrorCallback& error_callback) {
211   // This method is used only for Bluetooth classic.
212   NOTIMPLEMENTED() << __func__ << " Only BLE functionality is supported.";
213   error_callback.Run();
214 }
215 
Forget(const base::Closure & callback,const ErrorCallback & error_callback)216 void BluetoothDeviceCast::Forget(const base::Closure& callback,
217                                  const ErrorCallback& error_callback) {
218   NOTIMPLEMENTED() << __func__ << " Only BLE functionality is supported.";
219   error_callback.Run();
220 }
221 
ConnectToService(const BluetoothUUID & uuid,const ConnectToServiceCallback & callback,const ConnectToServiceErrorCallback & error_callback)222 void BluetoothDeviceCast::ConnectToService(
223     const BluetoothUUID& uuid,
224     const ConnectToServiceCallback& callback,
225     const ConnectToServiceErrorCallback& error_callback) {
226   NOTIMPLEMENTED() << __func__ << " GATT server mode not supported";
227   error_callback.Run("Not Implemented");
228 }
229 
ConnectToServiceInsecurely(const device::BluetoothUUID & uuid,const ConnectToServiceCallback & callback,const ConnectToServiceErrorCallback & error_callback)230 void BluetoothDeviceCast::ConnectToServiceInsecurely(
231     const device::BluetoothUUID& uuid,
232     const ConnectToServiceCallback& callback,
233     const ConnectToServiceErrorCallback& error_callback) {
234   NOTIMPLEMENTED() << __func__ << " GATT server mode not supported";
235   error_callback.Run("Not Implemented");
236 }
237 
UpdateWithScanResult(const chromecast::bluetooth::LeScanResult & result)238 bool BluetoothDeviceCast::UpdateWithScanResult(
239     const chromecast::bluetooth::LeScanResult& result) {
240   DVLOG(3) << __func__;
241   bool changed = false;
242 
243   base::Optional<std::string> result_name = result.Name();
244 
245   // Advertisements for the same device can use different names. For now, the
246   // last name wins. An empty string represents no name.
247   // TODO(slan): Make sure that this doesn't spam us with name changes.
248   if (result_name != name_) {
249     changed = true;
250     name_ = std::move(result_name);
251   }
252 
253   // Replace |device_uuids_| with newly advertised services. Currently this just
254   // replaces them, but depending on what we see in the field, we may need to
255   // take the union here instead. Note that this would require eviction of stale
256   // services, preferably from the LeScanManager.
257   // TODO(slan): Think about whether this is needed.
258   UUIDSet prev_uuids = device_uuids_.GetUUIDs();
259   UUIDSet new_uuids = ExtractServiceUuids(result);
260   if (prev_uuids != new_uuids) {
261     device_uuids_.ReplaceAdvertisedUUIDs(
262         UUIDList(new_uuids.begin(), new_uuids.end()));
263     changed = true;
264   }
265 
266   // Extract service data from the advertisement.
267   ServiceDataMap service_data = ExtractServiceData(result);
268   if (service_data != service_data_) {
269     service_data_ = std::move(service_data);
270     changed = true;
271   }
272 
273   // Extract manufacturer data from the advertisement.
274   ManufacturerDataMap manufacturer_data = ExtractManufacturerData(result);
275   if (manufacturer_data_ != manufacturer_data) {
276     manufacturer_data_ = manufacturer_data;
277     changed = true;
278   }
279 
280   return changed;
281 }
282 
SetConnected(bool connected)283 bool BluetoothDeviceCast::SetConnected(bool connected) {
284   DVLOG(2) << __func__ << " connected: " << connected;
285   bool was_connected = connected_;
286 
287   // Set the new state *before* calling the protected methods below. They may
288   // synchronously query the state of the device.
289   connected_ = connected;
290 
291   // Update state in the base class. This will cause pending callbacks to be
292   // fired.
293   if (!was_connected && connected) {
294     DidConnectGatt();
295     remote_device_->GetServices(base::BindOnce(
296         &BluetoothDeviceCast::OnGetServices, weak_factory_.GetWeakPtr()));
297   } else if (was_connected && !connected) {
298     DidDisconnectGatt();
299   }
300 
301   // Return true if the value of |connected_| changed.
302   return was_connected != connected;
303 }
304 
OnGetServices(std::vector<scoped_refptr<chromecast::bluetooth::RemoteService>> services)305 void BluetoothDeviceCast::OnGetServices(
306     std::vector<scoped_refptr<chromecast::bluetooth::RemoteService>> services) {
307   DVLOG(2) << __func__;
308   gatt_services_.clear();
309 
310   // Add new services.
311   for (auto& service : services) {
312     auto key = GetCanonicalBluetoothUuid(service->uuid());
313     auto cast_service = std::make_unique<BluetoothRemoteGattServiceCast>(
314         this, std::move(service));
315     DCHECK_EQ(key, cast_service->GetIdentifier());
316     gatt_services_[key] = std::move(cast_service);
317   }
318 
319   device_uuids_.ReplaceServiceUUIDs(gatt_services_);
320   SetGattServicesDiscoveryComplete(true);
321   adapter_->NotifyGattServicesDiscovered(this);
322 }
323 
UpdateCharacteristicValue(scoped_refptr<chromecast::bluetooth::RemoteCharacteristic> characteristic,std::vector<uint8_t> value,OnValueUpdatedCallback callback)324 bool BluetoothDeviceCast::UpdateCharacteristicValue(
325     scoped_refptr<chromecast::bluetooth::RemoteCharacteristic> characteristic,
326     std::vector<uint8_t> value,
327     OnValueUpdatedCallback callback) {
328   auto uuid = UuidToBluetoothUUID(characteristic->uuid());
329   // TODO(slan): Consider using a look-up to find characteristics instead. This
330   // approach could be inefficient if a device has a lot of characteristics.
331   for (const auto& it : gatt_services_) {
332     for (auto* c : it.second->GetCharacteristics()) {
333       if (c->GetUUID() == uuid) {
334         static_cast<BluetoothRemoteGattCharacteristicCast*>(c)->SetValue(value);
335         std::move(callback).Run(c, value);
336         return true;
337       }
338     }
339   }
340   LOG(WARNING) << GetAddress() << " does not have a service with "
341                << " characteristic " << uuid.canonical_value();
342   return false;
343 }
344 
CreateGattConnectionImpl(base::Optional<BluetoothUUID> service_uuid)345 void BluetoothDeviceCast::CreateGattConnectionImpl(
346     base::Optional<BluetoothUUID> service_uuid) {
347   DVLOG(2) << __func__ << " " << pending_connect_;
348   if (pending_connect_)
349     return;
350   pending_connect_ = true;
351   remote_device_->Connect(base::BindOnce(&BluetoothDeviceCast::OnConnect,
352                                          weak_factory_.GetWeakPtr()));
353 }
354 
DisconnectGatt()355 void BluetoothDeviceCast::DisconnectGatt() {
356   // The device is intentionally not disconnected.
357 }
358 
OnConnect(bool success)359 void BluetoothDeviceCast::OnConnect(bool success) {
360   DVLOG(2) << __func__ << " success:" << success;
361   pending_connect_ = false;
362   if (!success)
363     DidFailToConnectGatt(ERROR_FAILED);
364 }
365 
366 }  // namespace device
367