OLD | NEW |
1 // Copyright 2015 The Chromium Authors. All rights reserved. | 1 // Copyright 2015 The Chromium Authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "device/bluetooth/bluetooth_low_energy_device_mac.h" | 5 #include "device/bluetooth/bluetooth_low_energy_device_mac.h" |
6 | 6 |
7 #import <CoreFoundation/CoreFoundation.h> | 7 #import <CoreFoundation/CoreFoundation.h> |
8 #include <stddef.h> | 8 #include <stddef.h> |
9 | 9 |
10 #include "base/mac/mac_util.h" | 10 #include "base/mac/mac_util.h" |
(...skipping 158 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
169 | 169 |
170 void BluetoothLowEnergyDeviceMac::ConnectToServiceInsecurely( | 170 void BluetoothLowEnergyDeviceMac::ConnectToServiceInsecurely( |
171 const device::BluetoothUUID& uuid, | 171 const device::BluetoothUUID& uuid, |
172 const ConnectToServiceCallback& callback, | 172 const ConnectToServiceCallback& callback, |
173 const ConnectToServiceErrorCallback& error_callback) { | 173 const ConnectToServiceErrorCallback& error_callback) { |
174 NOTIMPLEMENTED(); | 174 NOTIMPLEMENTED(); |
175 } | 175 } |
176 | 176 |
177 void BluetoothLowEnergyDeviceMac::CreateGattConnectionImpl() { | 177 void BluetoothLowEnergyDeviceMac::CreateGattConnectionImpl() { |
178 if (!IsGattConnected()) { | 178 if (!IsGattConnected()) { |
| 179 VLOG(1) << *this << ": CreateGattConnection."; |
179 GetMacAdapter()->CreateGattConnection(this); | 180 GetMacAdapter()->CreateGattConnection(this); |
180 } | 181 } |
181 } | 182 } |
182 | 183 |
183 void BluetoothLowEnergyDeviceMac::DisconnectGatt() { | 184 void BluetoothLowEnergyDeviceMac::DisconnectGatt() { |
| 185 VLOG(1) << *this << ": Disconnect."; |
184 GetMacAdapter()->DisconnectGatt(this); | 186 GetMacAdapter()->DisconnectGatt(this); |
185 } | 187 } |
186 | 188 |
187 void BluetoothLowEnergyDeviceMac::DidDiscoverPrimaryServices(NSError* error) { | 189 void BluetoothLowEnergyDeviceMac::DidDiscoverPrimaryServices(NSError* error) { |
188 --discovery_pending_count_; | 190 --discovery_pending_count_; |
189 if (discovery_pending_count_ < 0) { | 191 if (discovery_pending_count_ < 0) { |
190 // This should never happens, just in case it happens with a device, | 192 // This should never happens, just in case it happens with a device, |
191 // discovery_pending_count_ is set back to 0. | 193 // discovery_pending_count_ is set back to 0. |
192 VLOG(1) << GetName()->c_str() | 194 VLOG(1) << *this |
193 << ": BluetoothLowEnergyDeviceMac::discovery_pending_count_ " | 195 << ": BluetoothLowEnergyDeviceMac::discovery_pending_count_ " |
194 << discovery_pending_count_; | 196 << discovery_pending_count_; |
195 discovery_pending_count_ = 0; | 197 discovery_pending_count_ = 0; |
196 return; | 198 return; |
197 } | 199 } |
198 if (error) { | 200 if (error) { |
199 // TODO(http://crbug.com/609320): Need to pass the error. | 201 // TODO(http://crbug.com/609320): Need to pass the error. |
200 // TODO(http://crbug.com/609844): Decide what to do if discover failed | 202 // TODO(http://crbug.com/609844): Decide what to do if discover failed |
201 // a device services. | 203 // a device services. |
202 VLOG(1) << "Can't discover primary services: " | 204 VLOG(1) << *this << ": Can't discover primary services: " |
203 << error.localizedDescription.UTF8String << " (" << error.domain | 205 << error.localizedDescription.UTF8String << " (" << error.domain |
204 << ": " << error.code << ")"; | 206 << ": " << error.code << ")."; |
205 return; | 207 return; |
206 } | 208 } |
207 VLOG(1) << "DidDiscoverPrimaryServices, pending count: " | |
208 << discovery_pending_count_; | |
209 | 209 |
210 if (!IsGattConnected()) { | 210 if (!IsGattConnected()) { |
211 // Don't create services if the device disconnected. | 211 // Don't create services if the device disconnected. |
| 212 VLOG(1) << *this << ": DidDiscoverPrimaryServices, gatt not connected."; |
212 return; | 213 return; |
213 } | 214 } |
| 215 VLOG(1) << *this << ": DidDiscoverPrimaryServices, pending count: " |
| 216 << discovery_pending_count_; |
214 | 217 |
215 for (CBService* cb_service in GetPeripheral().services) { | 218 for (CBService* cb_service in GetPeripheral().services) { |
216 BluetoothRemoteGattServiceMac* gatt_service = | 219 BluetoothRemoteGattServiceMac* gatt_service = |
217 GetBluetoothRemoteGattService(cb_service); | 220 GetBluetoothRemoteGattService(cb_service); |
218 if (!gatt_service) { | 221 if (!gatt_service) { |
219 gatt_service = new BluetoothRemoteGattServiceMac(this, cb_service, | 222 gatt_service = new BluetoothRemoteGattServiceMac(this, cb_service, |
220 true /* is_primary */); | 223 true /* is_primary */); |
221 auto result_iter = gatt_services_.insert(std::make_pair( | 224 auto result_iter = gatt_services_.insert(std::make_pair( |
222 gatt_service->GetIdentifier(), base::WrapUnique(gatt_service))); | 225 gatt_service->GetIdentifier(), base::WrapUnique(gatt_service))); |
223 DCHECK(result_iter.second); | 226 DCHECK(result_iter.second); |
| 227 VLOG(1) << *gatt_service << ": New service."; |
224 adapter_->NotifyGattServiceAdded(gatt_service); | 228 adapter_->NotifyGattServiceAdded(gatt_service); |
| 229 } else { |
| 230 VLOG(1) << *gatt_service << ": Known service."; |
225 } | 231 } |
226 } | 232 } |
227 if (discovery_pending_count_ == 0) { | 233 if (discovery_pending_count_ == 0) { |
228 for (auto it = gatt_services_.begin(); it != gatt_services_.end(); ++it) { | 234 for (auto it = gatt_services_.begin(); it != gatt_services_.end(); ++it) { |
229 device::BluetoothRemoteGattService* gatt_service = it->second.get(); | 235 device::BluetoothRemoteGattService* gatt_service = it->second.get(); |
230 device::BluetoothRemoteGattServiceMac* gatt_service_mac = | 236 device::BluetoothRemoteGattServiceMac* gatt_service_mac = |
231 static_cast<BluetoothRemoteGattServiceMac*>(gatt_service); | 237 static_cast<BluetoothRemoteGattServiceMac*>(gatt_service); |
232 gatt_service_mac->DiscoverCharacteristics(); | 238 gatt_service_mac->DiscoverCharacteristics(); |
233 } | 239 } |
234 SendNotificationIfDiscoveryComplete(); | 240 SendNotificationIfDiscoveryComplete(); |
235 } | 241 } |
236 } | 242 } |
237 | 243 |
238 void BluetoothLowEnergyDeviceMac::DidDiscoverCharacteristics( | 244 void BluetoothLowEnergyDeviceMac::DidDiscoverCharacteristics( |
239 CBService* cb_service, | 245 CBService* cb_service, |
240 NSError* error) { | 246 NSError* error) { |
241 if (error) { | 247 if (error) { |
242 // TODO(http://crbug.com/609320): Need to pass the error. | 248 // TODO(http://crbug.com/609320): Need to pass the error. |
243 // TODO(http://crbug.com/609844): Decide what to do if discover failed | 249 // TODO(http://crbug.com/609844): Decide what to do if discover failed |
244 VLOG(1) << "Can't discover characteristics: " | 250 VLOG(1) << *this << ": Can't discover characteristics: " |
245 << error.localizedDescription.UTF8String << " (" << error.domain | 251 << error.localizedDescription.UTF8String << " (" << error.domain |
246 << ": " << error.code << ")"; | 252 << ": " << error.code << ")."; |
247 return; | 253 return; |
248 } | 254 } |
249 VLOG(1) << "DidDiscoverCharacteristics."; | |
250 | 255 |
251 if (!IsGattConnected()) { | 256 if (!IsGattConnected()) { |
| 257 VLOG(1) << *this << ": DidDiscoverCharacteristics, gatt disconnected."; |
252 // Don't create characteristics if the device disconnected. | 258 // Don't create characteristics if the device disconnected. |
253 return; | 259 return; |
254 } | 260 } |
255 | 261 |
256 BluetoothRemoteGattServiceMac* gatt_service = | 262 BluetoothRemoteGattServiceMac* gatt_service = |
257 GetBluetoothRemoteGattService(cb_service); | 263 GetBluetoothRemoteGattService(cb_service); |
258 DCHECK(gatt_service); | 264 DCHECK(gatt_service); |
259 gatt_service->DidDiscoverCharacteristics(); | 265 gatt_service->DidDiscoverCharacteristics(); |
260 SendNotificationIfDiscoveryComplete(); | 266 SendNotificationIfDiscoveryComplete(); |
261 } | 267 } |
262 | 268 |
263 void BluetoothLowEnergyDeviceMac::DidModifyServices( | 269 void BluetoothLowEnergyDeviceMac::DidModifyServices( |
264 NSArray* invalidatedServices) { | 270 NSArray* invalidatedServices) { |
265 VLOG(1) << "DidModifyServices: "; | 271 VLOG(1) << *this << ": DidModifyServices: " |
| 272 << " invalidated services " |
| 273 << base::SysNSStringToUTF8([invalidatedServices description]); |
266 for (CBService* cb_service in invalidatedServices) { | 274 for (CBService* cb_service in invalidatedServices) { |
267 BluetoothRemoteGattServiceMac* gatt_service = | 275 BluetoothRemoteGattServiceMac* gatt_service = |
268 GetBluetoothRemoteGattService(cb_service); | 276 GetBluetoothRemoteGattService(cb_service); |
269 DCHECK(gatt_service); | 277 DCHECK(gatt_service); |
270 VLOG(1) << gatt_service->GetUUID().canonical_value(); | 278 VLOG(1) << gatt_service->GetUUID().canonical_value(); |
271 std::unique_ptr<BluetoothRemoteGattService> scoped_service = | 279 std::unique_ptr<BluetoothRemoteGattService> scoped_service = |
272 std::move(gatt_services_[gatt_service->GetIdentifier()]); | 280 std::move(gatt_services_[gatt_service->GetIdentifier()]); |
273 gatt_services_.erase(gatt_service->GetIdentifier()); | 281 gatt_services_.erase(gatt_service->GetIdentifier()); |
274 adapter_->NotifyGattServiceRemoved(scoped_service.get()); | 282 adapter_->NotifyGattServiceRemoved(scoped_service.get()); |
275 } | 283 } |
276 device_uuids_.ClearServiceUUIDs(); | 284 device_uuids_.ClearServiceUUIDs(); |
277 SetGattServicesDiscoveryComplete(false); | 285 SetGattServicesDiscoveryComplete(false); |
278 adapter_->NotifyDeviceChanged(this); | 286 adapter_->NotifyDeviceChanged(this); |
279 DiscoverPrimaryServices(); | 287 DiscoverPrimaryServices(); |
280 } | 288 } |
281 | 289 |
282 void BluetoothLowEnergyDeviceMac::DidUpdateValue( | 290 void BluetoothLowEnergyDeviceMac::DidUpdateValue( |
283 CBCharacteristic* characteristic, | 291 CBCharacteristic* characteristic, |
284 NSError* error) { | 292 NSError* error) { |
285 VLOG(1) << "DidUpdateValue."; | |
286 BluetoothRemoteGattServiceMac* gatt_service = | 293 BluetoothRemoteGattServiceMac* gatt_service = |
287 GetBluetoothRemoteGattService(characteristic.service); | 294 GetBluetoothRemoteGattService(characteristic.service); |
288 DCHECK(gatt_service); | 295 DCHECK(gatt_service); |
289 gatt_service->DidUpdateValue(characteristic, error); | 296 gatt_service->DidUpdateValue(characteristic, error); |
290 } | 297 } |
291 | 298 |
292 void BluetoothLowEnergyDeviceMac::DidWriteValue( | 299 void BluetoothLowEnergyDeviceMac::DidWriteValue( |
293 CBCharacteristic* characteristic, | 300 CBCharacteristic* characteristic, |
294 NSError* error) { | 301 NSError* error) { |
295 VLOG(1) << "DidWriteValue."; | |
296 BluetoothRemoteGattServiceMac* gatt_service = | 302 BluetoothRemoteGattServiceMac* gatt_service = |
297 GetBluetoothRemoteGattService(characteristic.service); | 303 GetBluetoothRemoteGattService(characteristic.service); |
298 DCHECK(gatt_service); | 304 DCHECK(gatt_service); |
299 gatt_service->DidWriteValue(characteristic, error); | 305 gatt_service->DidWriteValue(characteristic, error); |
300 } | 306 } |
301 | 307 |
302 void BluetoothLowEnergyDeviceMac::DidUpdateNotificationState( | 308 void BluetoothLowEnergyDeviceMac::DidUpdateNotificationState( |
303 CBCharacteristic* characteristic, | 309 CBCharacteristic* characteristic, |
304 NSError* error) { | 310 NSError* error) { |
305 VLOG(1) << "DidUpdateNotificationState"; | |
306 BluetoothRemoteGattServiceMac* gatt_service = | 311 BluetoothRemoteGattServiceMac* gatt_service = |
307 GetBluetoothRemoteGattService(characteristic.service); | 312 GetBluetoothRemoteGattService(characteristic.service); |
308 DCHECK(gatt_service); | 313 DCHECK(gatt_service); |
309 gatt_service->DidUpdateNotificationState(characteristic, error); | 314 gatt_service->DidUpdateNotificationState(characteristic, error); |
310 } | 315 } |
311 | 316 |
312 void BluetoothLowEnergyDeviceMac::DidDiscoverDescriptors( | 317 void BluetoothLowEnergyDeviceMac::DidDiscoverDescriptors( |
313 CBCharacteristic* cb_characteristic, | 318 CBCharacteristic* cb_characteristic, |
314 NSError* error) { | 319 NSError* error) { |
315 if (error) { | 320 if (error) { |
316 // TODO(http://crbug.com/609320): Need to pass the error. | 321 // TODO(http://crbug.com/609320): Need to pass the error. |
317 // TODO(http://crbug.com/609844): Decide what to do if discover failed | 322 // TODO(http://crbug.com/609844): Decide what to do if discover failed |
318 VLOG(1) << "Can't discover descriptors: " | 323 VLOG(1) << *this << ": Can't discover descriptors: " |
319 << error.localizedDescription.UTF8String << " (" << error.domain | 324 << error.localizedDescription.UTF8String << " (" << error.domain |
320 << ": " << error.code << ")"; | 325 << ": " << error.code << ")."; |
321 return; | 326 return; |
322 } | 327 } |
323 VLOG(1) << "DidDiscoverDescriptors."; | |
324 if (!IsGattConnected()) { | 328 if (!IsGattConnected()) { |
| 329 VLOG(1) << *this << ": DidDiscoverDescriptors, disconnected."; |
325 // Don't discover descriptors if the device disconnected. | 330 // Don't discover descriptors if the device disconnected. |
326 return; | 331 return; |
327 } | 332 } |
328 BluetoothRemoteGattServiceMac* gatt_service = | 333 BluetoothRemoteGattServiceMac* gatt_service = |
329 GetBluetoothRemoteGattService(cb_characteristic.service); | 334 GetBluetoothRemoteGattService(cb_characteristic.service); |
330 DCHECK(gatt_service); | 335 DCHECK(gatt_service); |
331 gatt_service->DidDiscoverDescriptors(cb_characteristic); | 336 gatt_service->DidDiscoverDescriptors(cb_characteristic); |
332 SendNotificationIfDiscoveryComplete(); | 337 SendNotificationIfDiscoveryComplete(); |
333 } | 338 } |
334 | 339 |
(...skipping 11 matching lines...) Expand all Loading... |
346 CBPeripheral* peripheral) { | 351 CBPeripheral* peripheral) { |
347 const size_t kCanonicalAddressNumberOfBytes = 6; | 352 const size_t kCanonicalAddressNumberOfBytes = 6; |
348 char raw[kCanonicalAddressNumberOfBytes]; | 353 char raw[kCanonicalAddressNumberOfBytes]; |
349 crypto::SHA256HashString(GetPeripheralIdentifier(peripheral), raw, | 354 crypto::SHA256HashString(GetPeripheralIdentifier(peripheral), raw, |
350 sizeof(raw)); | 355 sizeof(raw)); |
351 std::string hash = base::HexEncode(raw, sizeof(raw)); | 356 std::string hash = base::HexEncode(raw, sizeof(raw)); |
352 return BluetoothDevice::CanonicalizeAddress(hash); | 357 return BluetoothDevice::CanonicalizeAddress(hash); |
353 } | 358 } |
354 | 359 |
355 void BluetoothLowEnergyDeviceMac::DiscoverPrimaryServices() { | 360 void BluetoothLowEnergyDeviceMac::DiscoverPrimaryServices() { |
356 VLOG(1) << "DidDiscoverDescriptors pending count" << discovery_pending_count_; | 361 VLOG(1) << *this << ": DiscoverPrimaryServices, pending count " |
| 362 << discovery_pending_count_; |
357 ++discovery_pending_count_; | 363 ++discovery_pending_count_; |
358 [GetPeripheral() discoverServices:nil]; | 364 [GetPeripheral() discoverServices:nil]; |
359 } | 365 } |
360 | 366 |
361 void BluetoothLowEnergyDeviceMac::SendNotificationIfDiscoveryComplete() { | 367 void BluetoothLowEnergyDeviceMac::SendNotificationIfDiscoveryComplete() { |
362 // Notify when all services have been discovered. | 368 // Notify when all services have been discovered. |
363 bool discovery_complete = | 369 bool discovery_complete = |
364 discovery_pending_count_ == 0 && | 370 discovery_pending_count_ == 0 && |
365 std::find_if_not( | 371 std::find_if_not( |
366 gatt_services_.begin(), | 372 gatt_services_.begin(), |
367 gatt_services_.end(), [](GattServiceMap::value_type & pair) { | 373 gatt_services_.end(), [](GattServiceMap::value_type & pair) { |
368 BluetoothRemoteGattService* gatt_service = pair.second.get(); | 374 BluetoothRemoteGattService* gatt_service = pair.second.get(); |
369 return static_cast<BluetoothRemoteGattServiceMac*>(gatt_service) | 375 return static_cast<BluetoothRemoteGattServiceMac*>(gatt_service) |
370 ->IsDiscoveryComplete(); | 376 ->IsDiscoveryComplete(); |
371 }) == gatt_services_.end(); | 377 }) == gatt_services_.end(); |
372 if (discovery_complete) { | 378 if (discovery_complete) { |
| 379 VLOG(1) << *this << ": Discovery complete."; |
373 device_uuids_.ReplaceServiceUUIDs(gatt_services_); | 380 device_uuids_.ReplaceServiceUUIDs(gatt_services_); |
374 SetGattServicesDiscoveryComplete(true); | 381 SetGattServicesDiscoveryComplete(true); |
375 adapter_->NotifyGattServicesDiscovered(this); | 382 adapter_->NotifyGattServicesDiscovered(this); |
376 adapter_->NotifyDeviceChanged(this); | 383 adapter_->NotifyDeviceChanged(this); |
377 } | 384 } |
378 } | 385 } |
379 | 386 |
380 device::BluetoothAdapterMac* BluetoothLowEnergyDeviceMac::GetMacAdapter() { | 387 device::BluetoothAdapterMac* BluetoothLowEnergyDeviceMac::GetMacAdapter() { |
381 return static_cast<BluetoothAdapterMac*>(this->adapter_); | 388 return static_cast<BluetoothAdapterMac*>(this->adapter_); |
382 } | 389 } |
383 | 390 |
384 CBPeripheral* BluetoothLowEnergyDeviceMac::GetPeripheral() { | 391 CBPeripheral* BluetoothLowEnergyDeviceMac::GetPeripheral() { |
385 return peripheral_; | 392 return peripheral_; |
386 } | 393 } |
387 | 394 |
388 device::BluetoothRemoteGattServiceMac* | 395 device::BluetoothRemoteGattServiceMac* |
389 BluetoothLowEnergyDeviceMac::GetBluetoothRemoteGattService( | 396 BluetoothLowEnergyDeviceMac::GetBluetoothRemoteGattService( |
390 CBService* cb_service) const { | 397 CBService* cb_service) const { |
391 for (auto it = gatt_services_.begin(); it != gatt_services_.end(); ++it) { | 398 for (auto it = gatt_services_.begin(); it != gatt_services_.end(); ++it) { |
392 device::BluetoothRemoteGattService* gatt_service = it->second.get(); | 399 device::BluetoothRemoteGattService* gatt_service = it->second.get(); |
393 device::BluetoothRemoteGattServiceMac* gatt_service_mac = | 400 device::BluetoothRemoteGattServiceMac* gatt_service_mac = |
394 static_cast<BluetoothRemoteGattServiceMac*>(gatt_service); | 401 static_cast<BluetoothRemoteGattServiceMac*>(gatt_service); |
395 if (gatt_service_mac->GetService() == cb_service) | 402 if (gatt_service_mac->GetService() == cb_service) |
396 return gatt_service_mac; | 403 return gatt_service_mac; |
397 } | 404 } |
398 return nullptr; | 405 return nullptr; |
399 } | 406 } |
400 | 407 |
401 void BluetoothLowEnergyDeviceMac::DidDisconnectPeripheral(NSError* error) { | 408 void BluetoothLowEnergyDeviceMac::DidDisconnectPeripheral(NSError* error) { |
| 409 VLOG(1) << *this << ": Disconnected from peripheral."; |
| 410 if (error) { |
| 411 VLOG(1) << *this << ": Bluetooth error, domain: " << error.domain.UTF8String |
| 412 << ", error code: " << error.code; |
| 413 } |
402 SetGattServicesDiscoveryComplete(false); | 414 SetGattServicesDiscoveryComplete(false); |
403 // Removing all services at once to ensure that calling GetGattService on | 415 // Removing all services at once to ensure that calling GetGattService on |
404 // removed service in GattServiceRemoved returns null. | 416 // removed service in GattServiceRemoved returns null. |
405 GattServiceMap gatt_services_swapped; | 417 GattServiceMap gatt_services_swapped; |
406 gatt_services_swapped.swap(gatt_services_); | 418 gatt_services_swapped.swap(gatt_services_); |
407 gatt_services_swapped.clear(); | 419 gatt_services_swapped.clear(); |
408 device_uuids_.ClearServiceUUIDs(); | 420 device_uuids_.ClearServiceUUIDs(); |
409 // There are two cases in which this function will be called: | 421 // There are two cases in which this function will be called: |
410 // 1. When the connection to the device breaks (either because | 422 // 1. When the connection to the device breaks (either because |
411 // we closed it or the device closed it). | 423 // we closed it or the device closed it). |
412 // 2. When we cancel a pending connection request. | 424 // 2. When we cancel a pending connection request. |
413 if (create_gatt_connection_error_callbacks_.empty()) { | 425 if (create_gatt_connection_error_callbacks_.empty()) { |
414 // If there are no pending callbacks then the connection broke (#1). | 426 // If there are no pending callbacks then the connection broke (#1). |
415 DidDisconnectGatt(true /* notifyDeviceChanged */); | 427 DidDisconnectGatt(true /* notifyDeviceChanged */); |
416 return; | 428 return; |
417 } | 429 } |
418 // Else we canceled the connection request (#2). | 430 // Else we canceled the connection request (#2). |
419 // TODO(http://crbug.com/585897): Need to pass the error. | 431 // TODO(http://crbug.com/585897): Need to pass the error. |
420 DidFailToConnectGatt(BluetoothDevice::ConnectErrorCode::ERROR_FAILED); | 432 DidFailToConnectGatt(BluetoothDevice::ConnectErrorCode::ERROR_FAILED); |
421 } | 433 } |
| 434 |
| 435 namespace device { |
| 436 |
| 437 std::ostream& operator<<(std::ostream& out, |
| 438 const BluetoothLowEnergyDeviceMac& device) { |
| 439 // TODO(crbug.com/703878): Should use |
| 440 // BluetoothLowEnergyDeviceMac::GetNameForDisplay() instead. |
| 441 base::Optional<std::string> name = device.GetName(); |
| 442 const char* name_cstr = name ? name->c_str() : ""; |
| 443 return out << "<BluetoothLowEnergyDeviceMac " << device.GetAddress() << "/" |
| 444 << &device << ", \"" << name_cstr << "\">"; |
| 445 } |
| 446 } // namespace device |
OLD | NEW |