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