OLD | NEW |
| (Empty) |
1 // Copyright (c) 2012 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/bluetooth_device_chromeos.h" | |
6 | |
7 #include <map> | |
8 #include <string> | |
9 #include <vector> | |
10 | |
11 #include "base/bind.h" | |
12 #include "base/command_line.h" | |
13 #include "base/logging.h" | |
14 #include "base/memory/scoped_vector.h" | |
15 #include "base/memory/weak_ptr.h" | |
16 #include "base/string16.h" | |
17 #include "base/string_util.h" | |
18 #include "base/values.h" | |
19 #include "chromeos/dbus/bluetooth_adapter_client.h" | |
20 #include "chromeos/dbus/bluetooth_agent_service_provider.h" | |
21 #include "chromeos/dbus/bluetooth_device_client.h" | |
22 #include "chromeos/dbus/bluetooth_input_client.h" | |
23 #include "chromeos/dbus/bluetooth_out_of_band_client.h" | |
24 #include "chromeos/dbus/dbus_thread_manager.h" | |
25 #include "chromeos/dbus/introspectable_client.h" | |
26 #include "dbus/bus.h" | |
27 #include "dbus/object_path.h" | |
28 #include "device/bluetooth/bluetooth_adapter_chromeos.h" | |
29 #include "device/bluetooth/bluetooth_out_of_band_pairing_data.h" | |
30 #include "device/bluetooth/bluetooth_service_record.h" | |
31 #include "device/bluetooth/bluetooth_service_record_chromeos.h" | |
32 #include "device/bluetooth/bluetooth_socket_chromeos.h" | |
33 #include "device/bluetooth/bluetooth_utils.h" | |
34 #include "third_party/cros_system_api/dbus/service_constants.h" | |
35 | |
36 using device::BluetoothDevice; | |
37 using device::BluetoothOutOfBandPairingData; | |
38 using device::BluetoothServiceRecord; | |
39 using device::BluetoothSocket; | |
40 | |
41 namespace { | |
42 | |
43 void DoNothingServiceRecordList(const BluetoothDevice::ServiceRecordList&) {} | |
44 | |
45 } // namespace | |
46 | |
47 namespace chromeos { | |
48 | |
49 BluetoothDeviceChromeOS::BluetoothDeviceChromeOS( | |
50 BluetoothAdapterChromeOS* adapter) | |
51 : BluetoothDevice(), | |
52 adapter_(adapter), | |
53 bluetooth_class_(0), | |
54 paired_(false), | |
55 trusted_(false), | |
56 connected_(false), | |
57 connectable_(true), | |
58 connecting_(false), | |
59 pairing_delegate_(NULL), | |
60 connecting_applications_counter_(0), | |
61 connecting_calls_(0), | |
62 service_records_loaded_(false), | |
63 weak_ptr_factory_(this) { | |
64 } | |
65 | |
66 BluetoothDeviceChromeOS::~BluetoothDeviceChromeOS() { | |
67 } | |
68 | |
69 uint32 BluetoothDeviceChromeOS::GetBluetoothClass() const { | |
70 return bluetooth_class_; | |
71 } | |
72 | |
73 std::string BluetoothDeviceChromeOS::GetDeviceName() const { | |
74 return name_; | |
75 } | |
76 | |
77 std::string BluetoothDeviceChromeOS::GetAddress() const { | |
78 return address_; | |
79 } | |
80 | |
81 uint16 BluetoothDeviceChromeOS::GetVendorID() const { | |
82 return 0; | |
83 } | |
84 | |
85 uint16 BluetoothDeviceChromeOS::GetProductID() const { | |
86 return 0; | |
87 } | |
88 | |
89 uint16 BluetoothDeviceChromeOS::GetDeviceID() const { | |
90 return 0; | |
91 } | |
92 | |
93 bool BluetoothDeviceChromeOS::IsPaired() const { | |
94 return paired_ || trusted_; | |
95 } | |
96 | |
97 bool BluetoothDeviceChromeOS::IsConnected() const { | |
98 return connected_; | |
99 } | |
100 | |
101 bool BluetoothDeviceChromeOS::IsConnectable() const { | |
102 return connectable_; | |
103 } | |
104 | |
105 bool BluetoothDeviceChromeOS::IsConnecting() const { | |
106 return connecting_; | |
107 } | |
108 | |
109 BluetoothDeviceChromeOS::ServiceList | |
110 BluetoothDeviceChromeOS::GetServices() const { | |
111 return service_uuids_; | |
112 } | |
113 | |
114 void BluetoothDeviceChromeOS::GetServiceRecords( | |
115 const ServiceRecordsCallback& callback, | |
116 const ErrorCallback& error_callback) { | |
117 DBusThreadManager::Get()->GetBluetoothDeviceClient()-> | |
118 DiscoverServices( | |
119 object_path_, | |
120 "", // empty pattern to browse all services | |
121 base::Bind(&BluetoothDeviceChromeOS::CollectServiceRecordsCallback, | |
122 weak_ptr_factory_.GetWeakPtr(), | |
123 callback, | |
124 base::Bind( | |
125 &BluetoothDeviceChromeOS::OnGetServiceRecordsError, | |
126 weak_ptr_factory_.GetWeakPtr(), | |
127 callback, | |
128 error_callback))); | |
129 } | |
130 | |
131 void BluetoothDeviceChromeOS::ProvidesServiceWithName( | |
132 const std::string& name, | |
133 const ProvidesServiceCallback& callback) { | |
134 GetServiceRecords( | |
135 base::Bind(&BluetoothDeviceChromeOS::SearchServicesForNameCallback, | |
136 weak_ptr_factory_.GetWeakPtr(), | |
137 name, | |
138 callback), | |
139 base::Bind(&BluetoothDeviceChromeOS::SearchServicesForNameErrorCallback, | |
140 weak_ptr_factory_.GetWeakPtr(), | |
141 callback)); | |
142 } | |
143 | |
144 bool BluetoothDeviceChromeOS::ExpectingPinCode() const { | |
145 return !pincode_callback_.is_null(); | |
146 } | |
147 | |
148 bool BluetoothDeviceChromeOS::ExpectingPasskey() const { | |
149 return !passkey_callback_.is_null(); | |
150 } | |
151 | |
152 bool BluetoothDeviceChromeOS::ExpectingConfirmation() const { | |
153 return !confirmation_callback_.is_null(); | |
154 } | |
155 | |
156 void BluetoothDeviceChromeOS::Connect( | |
157 PairingDelegate* pairing_delegate, | |
158 const base::Closure& callback, | |
159 const ConnectErrorCallback& error_callback) { | |
160 // This is safe because Connect() and its callbacks are called in the same | |
161 // thread. | |
162 connecting_calls_++; | |
163 if (!connecting_) { | |
164 connecting_ = true; | |
165 adapter_->NotifyDeviceChanged(this); | |
166 } | |
167 connecting_ = !!connecting_calls_; | |
168 // Set the decrement to be issued when either callback is called. | |
169 base::Closure wrapped_callback = base::Bind( | |
170 &BluetoothDeviceChromeOS::OnConnectCallbackCalled, | |
171 weak_ptr_factory_.GetWeakPtr(), | |
172 callback); | |
173 ConnectErrorCallback wrapped_error_callback = base::Bind( | |
174 &BluetoothDeviceChromeOS::OnConnectErrorCallbackCalled, | |
175 weak_ptr_factory_.GetWeakPtr(), | |
176 error_callback); | |
177 | |
178 if (IsPaired()) { | |
179 // Connection to already paired device. | |
180 ConnectApplications(wrapped_callback, wrapped_error_callback); | |
181 | |
182 } else if (!pairing_delegate || !IsPairable()) { | |
183 // No pairing delegate supplied, or unpairable device; initiate | |
184 // low-security connection only. | |
185 DBusThreadManager::Get()->GetBluetoothAdapterClient()-> | |
186 CreateDevice(adapter_->object_path_, | |
187 address_, | |
188 base::Bind(&BluetoothDeviceChromeOS::OnCreateDevice, | |
189 weak_ptr_factory_.GetWeakPtr(), | |
190 wrapped_callback, | |
191 wrapped_error_callback), | |
192 base::Bind(&BluetoothDeviceChromeOS::OnCreateDeviceError, | |
193 weak_ptr_factory_.GetWeakPtr(), | |
194 wrapped_error_callback)); | |
195 } else { | |
196 // Initiate high-security connection with pairing. | |
197 DCHECK(!pairing_delegate_); | |
198 pairing_delegate_ = pairing_delegate; | |
199 | |
200 // The agent path is relatively meaningless, we use the device address | |
201 // to generate it as we only support one pairing attempt at a time for | |
202 // a given bluetooth device. | |
203 DCHECK(agent_.get() == NULL); | |
204 | |
205 std::string agent_path_basename; | |
206 ReplaceChars(address_, ":", "_", &agent_path_basename); | |
207 dbus::ObjectPath agent_path("/org/chromium/bluetooth_agent/" + | |
208 agent_path_basename); | |
209 | |
210 dbus::Bus* system_bus = DBusThreadManager::Get()->GetSystemBus(); | |
211 if (system_bus) { | |
212 agent_.reset(BluetoothAgentServiceProvider::Create(system_bus, | |
213 agent_path, | |
214 this)); | |
215 } else { | |
216 agent_.reset(NULL); | |
217 } | |
218 | |
219 VLOG(1) << "Pairing: " << address_; | |
220 DBusThreadManager::Get()->GetBluetoothAdapterClient()-> | |
221 CreatePairedDevice( | |
222 adapter_->object_path_, | |
223 address_, | |
224 agent_path, | |
225 bluetooth_agent::kDisplayYesNoCapability, | |
226 base::Bind(&BluetoothDeviceChromeOS::OnCreateDevice, | |
227 weak_ptr_factory_.GetWeakPtr(), | |
228 wrapped_callback, | |
229 wrapped_error_callback), | |
230 base::Bind(&BluetoothDeviceChromeOS::OnCreateDeviceError, | |
231 weak_ptr_factory_.GetWeakPtr(), | |
232 wrapped_error_callback)); | |
233 } | |
234 } | |
235 | |
236 void BluetoothDeviceChromeOS::SetPinCode(const std::string& pincode) { | |
237 if (!agent_.get() || pincode_callback_.is_null()) | |
238 return; | |
239 | |
240 pincode_callback_.Run(SUCCESS, pincode); | |
241 pincode_callback_.Reset(); | |
242 } | |
243 | |
244 void BluetoothDeviceChromeOS::SetPasskey(uint32 passkey) { | |
245 if (!agent_.get() || passkey_callback_.is_null()) | |
246 return; | |
247 | |
248 passkey_callback_.Run(SUCCESS, passkey); | |
249 passkey_callback_.Reset(); | |
250 } | |
251 | |
252 void BluetoothDeviceChromeOS::ConfirmPairing() { | |
253 if (!agent_.get() || confirmation_callback_.is_null()) | |
254 return; | |
255 | |
256 confirmation_callback_.Run(SUCCESS); | |
257 confirmation_callback_.Reset(); | |
258 } | |
259 | |
260 void BluetoothDeviceChromeOS::RejectPairing() { | |
261 if (!agent_.get()) | |
262 return; | |
263 | |
264 if (!pincode_callback_.is_null()) { | |
265 pincode_callback_.Run(REJECTED, ""); | |
266 pincode_callback_.Reset(); | |
267 } | |
268 if (!passkey_callback_.is_null()) { | |
269 passkey_callback_.Run(REJECTED, 0); | |
270 passkey_callback_.Reset(); | |
271 } | |
272 if (!confirmation_callback_.is_null()) { | |
273 confirmation_callback_.Run(REJECTED); | |
274 confirmation_callback_.Reset(); | |
275 } | |
276 } | |
277 | |
278 void BluetoothDeviceChromeOS::CancelPairing() { | |
279 bool have_callback = false; | |
280 if (agent_.get()) { | |
281 if (!pincode_callback_.is_null()) { | |
282 pincode_callback_.Run(CANCELLED, ""); | |
283 pincode_callback_.Reset(); | |
284 have_callback = true; | |
285 } | |
286 if (!passkey_callback_.is_null()) { | |
287 passkey_callback_.Run(CANCELLED, 0); | |
288 passkey_callback_.Reset(); | |
289 have_callback = true; | |
290 } | |
291 if (!confirmation_callback_.is_null()) { | |
292 confirmation_callback_.Run(CANCELLED); | |
293 confirmation_callback_.Reset(); | |
294 have_callback = true; | |
295 } | |
296 } | |
297 | |
298 if (!have_callback) { | |
299 // User cancels the pairing process. | |
300 DBusThreadManager::Get()->GetBluetoothAdapterClient()->CancelDeviceCreation( | |
301 adapter_->object_path_, | |
302 address_, | |
303 base::Bind(&BluetoothDeviceChromeOS::OnCancelDeviceCreation, | |
304 weak_ptr_factory_.GetWeakPtr())); | |
305 | |
306 pairing_delegate_ = NULL; | |
307 agent_.reset(); | |
308 } | |
309 } | |
310 | |
311 void BluetoothDeviceChromeOS::Disconnect(const base::Closure& callback, | |
312 const ErrorCallback& error_callback) { | |
313 DBusThreadManager::Get()->GetBluetoothDeviceClient()-> | |
314 Disconnect(object_path_, | |
315 base::Bind(&BluetoothDeviceChromeOS::DisconnectCallback, | |
316 weak_ptr_factory_.GetWeakPtr(), | |
317 callback, | |
318 error_callback)); | |
319 | |
320 } | |
321 | |
322 void BluetoothDeviceChromeOS::Forget(const ErrorCallback& error_callback) { | |
323 DBusThreadManager::Get()->GetBluetoothAdapterClient()-> | |
324 RemoveDevice(adapter_->object_path_, | |
325 object_path_, | |
326 base::Bind(&BluetoothDeviceChromeOS::ForgetCallback, | |
327 weak_ptr_factory_.GetWeakPtr(), | |
328 error_callback)); | |
329 } | |
330 | |
331 void BluetoothDeviceChromeOS::ConnectToService(const std::string& service_uuid, | |
332 const SocketCallback& callback) { | |
333 GetServiceRecords( | |
334 base::Bind(&BluetoothDeviceChromeOS::GetServiceRecordsForConnectCallback, | |
335 weak_ptr_factory_.GetWeakPtr(), | |
336 service_uuid, | |
337 callback), | |
338 base::Bind( | |
339 &BluetoothDeviceChromeOS::GetServiceRecordsForConnectErrorCallback, | |
340 weak_ptr_factory_.GetWeakPtr(), | |
341 callback)); | |
342 } | |
343 | |
344 void BluetoothDeviceChromeOS::ConnectToProfile( | |
345 device::BluetoothProfile* profile, | |
346 const base::Closure& callback, | |
347 const ErrorCallback& error_callback) { | |
348 // TODO(keybuk): implement | |
349 } | |
350 | |
351 void BluetoothDeviceChromeOS::SetOutOfBandPairingData( | |
352 const BluetoothOutOfBandPairingData& data, | |
353 const base::Closure& callback, | |
354 const ErrorCallback& error_callback) { | |
355 DBusThreadManager::Get()->GetBluetoothOutOfBandClient()-> | |
356 AddRemoteData( | |
357 object_path_, | |
358 address_, | |
359 data, | |
360 base::Bind(&BluetoothDeviceChromeOS::OnRemoteDataCallback, | |
361 weak_ptr_factory_.GetWeakPtr(), | |
362 callback, | |
363 error_callback)); | |
364 } | |
365 | |
366 void BluetoothDeviceChromeOS::ClearOutOfBandPairingData( | |
367 const base::Closure& callback, | |
368 const ErrorCallback& error_callback) { | |
369 DBusThreadManager::Get()->GetBluetoothOutOfBandClient()-> | |
370 RemoveRemoteData( | |
371 object_path_, | |
372 address_, | |
373 base::Bind(&BluetoothDeviceChromeOS::OnRemoteDataCallback, | |
374 weak_ptr_factory_.GetWeakPtr(), | |
375 callback, | |
376 error_callback)); | |
377 } | |
378 | |
379 void BluetoothDeviceChromeOS::SetObjectPath( | |
380 const dbus::ObjectPath& object_path) { | |
381 DCHECK(object_path_ == dbus::ObjectPath("")); | |
382 object_path_ = object_path; | |
383 } | |
384 | |
385 void BluetoothDeviceChromeOS::RemoveObjectPath() { | |
386 DCHECK(object_path_ != dbus::ObjectPath("")); | |
387 object_path_ = dbus::ObjectPath(""); | |
388 } | |
389 | |
390 void BluetoothDeviceChromeOS::Update( | |
391 const BluetoothDeviceClient::Properties* properties, | |
392 bool update_state) { | |
393 std::string address = properties->address.value(); | |
394 std::string name = properties->name.value(); | |
395 uint32 bluetooth_class = properties->bluetooth_class.value(); | |
396 const std::vector<std::string>& uuids = properties->uuids.value(); | |
397 | |
398 if (!address.empty()) | |
399 address_ = address; | |
400 if (!name.empty()) | |
401 name_ = name; | |
402 if (bluetooth_class) | |
403 bluetooth_class_ = bluetooth_class; | |
404 if (!uuids.empty()) { | |
405 service_uuids_.clear(); | |
406 service_uuids_.assign(uuids.begin(), uuids.end()); | |
407 } | |
408 | |
409 if (update_state) { | |
410 // When the device reconnects and we don't have any service records for it, | |
411 // try to update the cache or fail silently. | |
412 if (!service_records_loaded_ && !connected_ && | |
413 properties->connected.value()) | |
414 GetServiceRecords(base::Bind(&DoNothingServiceRecordList), | |
415 base::Bind(&base::DoNothing)); | |
416 | |
417 paired_ = properties->paired.value(); | |
418 trusted_ = properties->trusted.value(); | |
419 connected_ = properties->connected.value(); | |
420 } | |
421 } | |
422 | |
423 void BluetoothDeviceChromeOS::OnCreateDevice( | |
424 const base::Closure& callback, | |
425 const ConnectErrorCallback& error_callback, | |
426 const dbus::ObjectPath& device_path) { | |
427 VLOG(1) << "Connection successful: " << device_path.value(); | |
428 if (object_path_.value().empty()) { | |
429 object_path_ = device_path; | |
430 } else { | |
431 LOG_IF(WARNING, object_path_ != device_path) | |
432 << "Conflicting device paths for objects, result gave: " | |
433 << device_path.value() << " but signal gave: " | |
434 << object_path_.value(); | |
435 } | |
436 | |
437 SetTrusted(); | |
438 | |
439 // In parallel with the |trusted| property change, call GetServiceRecords to | |
440 // retrieve the SDP from the device and then, either on success or failure, | |
441 // call ConnectApplications. | |
442 GetServiceRecords( | |
443 base::Bind(&BluetoothDeviceChromeOS::OnInitialGetServiceRecords, | |
444 weak_ptr_factory_.GetWeakPtr(), | |
445 callback, | |
446 error_callback), | |
447 base::Bind(&BluetoothDeviceChromeOS::OnInitialGetServiceRecordsError, | |
448 weak_ptr_factory_.GetWeakPtr(), | |
449 callback, | |
450 error_callback)); | |
451 } | |
452 | |
453 void BluetoothDeviceChromeOS::OnCreateDeviceError( | |
454 const ConnectErrorCallback& error_callback, | |
455 const std::string& error_name, | |
456 const std::string& error_message) { | |
457 // The default |error_code| is an unknown error. | |
458 ConnectErrorCode error_code = ERROR_UNKNOWN; | |
459 | |
460 // Report any error in the log, even if we know the possible source of it. | |
461 LOG(WARNING) << "Connection failed (on CreatePairedDevice): " | |
462 << "\"" << name_ << "\" (" << address_ << "): " | |
463 << error_name << ": \"" << error_message << "\""; | |
464 | |
465 // Determines the right error code from error_name, assuming the error name | |
466 // comes from CreatePairedDevice bluez function. | |
467 if (error_name == bluetooth_adapter::kErrorConnectionAttemptFailed) { | |
468 error_code = ERROR_FAILED; | |
469 } else if (error_name == bluetooth_adapter::kErrorAuthenticationFailed) { | |
470 error_code = ERROR_AUTH_FAILED; | |
471 } else if (error_name == bluetooth_adapter::kErrorAuthenticationRejected) { | |
472 error_code = ERROR_AUTH_REJECTED; | |
473 } else if (error_name == bluetooth_adapter::kErrorAuthenticationTimeout) { | |
474 error_code = ERROR_AUTH_TIMEOUT; | |
475 } | |
476 error_callback.Run(error_code); | |
477 } | |
478 | |
479 void BluetoothDeviceChromeOS::CollectServiceRecordsCallback( | |
480 const ServiceRecordsCallback& callback, | |
481 const ErrorCallback& error_callback, | |
482 const dbus::ObjectPath& device_path, | |
483 const BluetoothDeviceClient::ServiceMap& service_map, | |
484 bool success) { | |
485 if (!success) { | |
486 error_callback.Run(); | |
487 return; | |
488 } | |
489 | |
490 // Update the cache. No other thread is executing a GetServiceRecords | |
491 // callback, so it is safe to delete the previous objects here. | |
492 service_records_.clear(); | |
493 // TODO(deymo): Perhaps don't update the cache if the new SDP information is | |
494 // empty and we had something before. Some devices only answer this | |
495 // information while paired, and this callback could be called in any order if | |
496 // several calls to GetServiceRecords are made while initial pairing with the | |
497 // device. This requires more investigation. | |
498 for (BluetoothDeviceClient::ServiceMap::const_iterator i = | |
499 service_map.begin(); i != service_map.end(); ++i) { | |
500 service_records_.push_back( | |
501 new BluetoothServiceRecordChromeOS(address_, i->second)); | |
502 } | |
503 service_records_loaded_ = true; | |
504 | |
505 callback.Run(service_records_); | |
506 } | |
507 | |
508 void BluetoothDeviceChromeOS::SetTrusted() { | |
509 // Unconditionally send the property change, rather than checking the value | |
510 // first; there's no harm in doing this and it solves any race conditions | |
511 // with the property becoming true or false and this call happening before | |
512 // we get the D-Bus signal about the earlier change. | |
513 DBusThreadManager::Get()->GetBluetoothDeviceClient()-> | |
514 GetProperties(object_path_)->trusted.Set( | |
515 true, | |
516 base::Bind( | |
517 &BluetoothDeviceChromeOS::OnSetTrusted, | |
518 weak_ptr_factory_.GetWeakPtr())); | |
519 } | |
520 | |
521 void BluetoothDeviceChromeOS::OnSetTrusted(bool success) { | |
522 LOG_IF(WARNING, !success) << "Failed to set device as trusted: " << address_; | |
523 } | |
524 | |
525 void BluetoothDeviceChromeOS::OnInitialGetServiceRecords( | |
526 const base::Closure& callback, | |
527 const ConnectErrorCallback& error_callback, | |
528 const ServiceRecordList& list) { | |
529 // Connect application-layer protocols. | |
530 ConnectApplications(callback, error_callback); | |
531 } | |
532 | |
533 void BluetoothDeviceChromeOS::OnInitialGetServiceRecordsError( | |
534 const base::Closure& callback, | |
535 const ConnectErrorCallback& error_callback) { | |
536 // Ignore the error retrieving the service records and continue. | |
537 LOG(WARNING) << "Error retrieving SDP for " << address_ << " after pairing."; | |
538 // Connect application-layer protocols. | |
539 ConnectApplications(callback, error_callback); | |
540 } | |
541 | |
542 void BluetoothDeviceChromeOS::OnGetServiceRecordsError( | |
543 const ServiceRecordsCallback& callback, | |
544 const ErrorCallback& error_callback) { | |
545 if (service_records_loaded_) { | |
546 callback.Run(service_records_); | |
547 } else { | |
548 error_callback.Run(); | |
549 } | |
550 } | |
551 | |
552 void BluetoothDeviceChromeOS::OnConnectCallbackCalled( | |
553 const base::Closure& callback) { | |
554 // Update the connecting status. | |
555 bool prev_connecting = connecting_; | |
556 connecting_calls_--; | |
557 connecting_ = !!connecting_calls_; | |
558 callback.Run(); | |
559 if (prev_connecting != connecting_) adapter_->NotifyDeviceChanged(this); | |
560 } | |
561 | |
562 void BluetoothDeviceChromeOS::OnConnectErrorCallbackCalled( | |
563 const ConnectErrorCallback& error_callback, | |
564 enum ConnectErrorCode error_code) { | |
565 // Update the connecting status. | |
566 bool prev_connecting = connecting_; | |
567 connecting_calls_--; | |
568 connecting_ = !!connecting_calls_; | |
569 error_callback.Run(error_code); | |
570 if (prev_connecting != connecting_) adapter_->NotifyDeviceChanged(this); | |
571 } | |
572 | |
573 void BluetoothDeviceChromeOS::ConnectApplications( | |
574 const base::Closure& callback, | |
575 const ConnectErrorCallback& error_callback) { | |
576 // Introspect the device object to determine supported applications. | |
577 DBusThreadManager::Get()->GetIntrospectableClient()-> | |
578 Introspect(bluetooth_device::kBluetoothDeviceServiceName, | |
579 object_path_, | |
580 base::Bind(&BluetoothDeviceChromeOS::OnIntrospect, | |
581 weak_ptr_factory_.GetWeakPtr(), | |
582 callback, | |
583 error_callback)); | |
584 } | |
585 | |
586 void BluetoothDeviceChromeOS::OnIntrospect( | |
587 const base::Closure& callback, | |
588 const ConnectErrorCallback& error_callback, | |
589 const std::string& service_name, | |
590 const dbus::ObjectPath& device_path, | |
591 const std::string& xml_data, | |
592 bool success) { | |
593 if (!success) { | |
594 LOG(WARNING) << "Failed to determine supported applications: " << address_; | |
595 error_callback.Run(ERROR_UNKNOWN); | |
596 return; | |
597 } | |
598 | |
599 // The introspection data for the device object may list one or more | |
600 // additional D-Bus interfaces that BlueZ supports for this particular | |
601 // device. Send appropraite Connect calls for each of those interfaces | |
602 // to connect all of the application protocols for this device. | |
603 std::vector<std::string> interfaces = | |
604 IntrospectableClient::GetInterfacesFromIntrospectResult(xml_data); | |
605 | |
606 DCHECK_EQ(0, connecting_applications_counter_); | |
607 connecting_applications_counter_ = 0; | |
608 for (std::vector<std::string>::iterator iter = interfaces.begin(); | |
609 iter != interfaces.end(); ++iter) { | |
610 if (*iter == bluetooth_input::kBluetoothInputInterface) { | |
611 connecting_applications_counter_++; | |
612 // Supports Input interface. | |
613 DBusThreadManager::Get()->GetBluetoothInputClient()-> | |
614 Connect(object_path_, | |
615 base::Bind(&BluetoothDeviceChromeOS::OnConnect, | |
616 weak_ptr_factory_.GetWeakPtr(), | |
617 callback, | |
618 *iter), | |
619 base::Bind(&BluetoothDeviceChromeOS::OnConnectError, | |
620 weak_ptr_factory_.GetWeakPtr(), | |
621 error_callback, *iter)); | |
622 } | |
623 } | |
624 | |
625 // If OnConnect has been called for every call to Connect above, then this | |
626 // will decrement the counter to -1. In that case, call the callback | |
627 // directly as it has not been called by any of the OnConnect callbacks. | |
628 // This is safe because OnIntrospect and OnConnect run on the same thread. | |
629 connecting_applications_counter_--; | |
630 if (connecting_applications_counter_ == -1) | |
631 callback.Run(); | |
632 } | |
633 | |
634 void BluetoothDeviceChromeOS::OnConnect(const base::Closure& callback, | |
635 const std::string& interface_name, | |
636 const dbus::ObjectPath& device_path) { | |
637 VLOG(1) << "Application connection successful: " << device_path.value() | |
638 << ": " << interface_name; | |
639 | |
640 connecting_applications_counter_--; | |
641 // |callback| should only be called once, meaning it cannot be called before | |
642 // all requests have been started. The extra decrement after all requests | |
643 // have been started, and the check for -1 instead of 0 below, insure only a | |
644 // single call to |callback| will occur (provided OnConnect and OnIntrospect | |
645 // run on the same thread, which is true). | |
646 if (connecting_applications_counter_ == -1) { | |
647 connecting_applications_counter_ = 0; | |
648 SetTrusted(); | |
649 callback.Run(); | |
650 } | |
651 } | |
652 | |
653 void BluetoothDeviceChromeOS::OnConnectError( | |
654 const ConnectErrorCallback& error_callback, | |
655 const std::string& interface_name, | |
656 const dbus::ObjectPath& device_path, | |
657 const std::string& error_name, | |
658 const std::string& error_message) { | |
659 // The default |error_code| is an unknown error. | |
660 ConnectErrorCode error_code = ERROR_UNKNOWN; | |
661 | |
662 // Report any error in the log, even if we know the possible source of it. | |
663 LOG(WARNING) << "Connection failed (on Connect): " | |
664 << interface_name << ": " | |
665 << "\"" << name_ << "\" (" << address_ << "): " | |
666 << error_name << ": \"" << error_message << "\""; | |
667 | |
668 // Determines the right error code from error_name, assuming the error name | |
669 // comes from Connect bluez function. | |
670 if (error_name == bluetooth_adapter::kErrorFailed) { | |
671 error_code = ERROR_FAILED; | |
672 } else if (error_name == bluetooth_adapter::kErrorInProgress) { | |
673 error_code = ERROR_INPROGRESS; | |
674 } else if (error_name == bluetooth_adapter::kErrorNotSupported) { | |
675 error_code = ERROR_UNSUPPORTED_DEVICE; | |
676 } | |
677 | |
678 error_callback.Run(error_code); | |
679 } | |
680 | |
681 void BluetoothDeviceChromeOS::DisconnectCallback( | |
682 const base::Closure& callback, | |
683 const ErrorCallback& error_callback, | |
684 const dbus::ObjectPath& device_path, | |
685 bool success) { | |
686 DCHECK(device_path == object_path_); | |
687 if (success) { | |
688 VLOG(1) << "Disconnection successful: " << address_; | |
689 callback.Run(); | |
690 } else { | |
691 if (connected_) { | |
692 LOG(WARNING) << "Disconnection failed: " << address_; | |
693 error_callback.Run(); | |
694 } else { | |
695 VLOG(1) << "Disconnection failed on a already disconnected device: " | |
696 << address_; | |
697 callback.Run(); | |
698 } | |
699 } | |
700 } | |
701 | |
702 void BluetoothDeviceChromeOS::ForgetCallback( | |
703 const ErrorCallback& error_callback, | |
704 const dbus::ObjectPath& adapter_path, | |
705 bool success) { | |
706 // It's quite normal that this path never gets called on success; we use a | |
707 // weak pointer, and bluetoothd might send the DeviceRemoved signal before | |
708 // the method reply, in which case this object is deleted and the | |
709 // callback never takes place. Therefore don't do anything here for the | |
710 // success case. | |
711 if (!success) { | |
712 LOG(WARNING) << "Forget failed: " << address_; | |
713 error_callback.Run(); | |
714 } | |
715 } | |
716 | |
717 void BluetoothDeviceChromeOS::OnCancelDeviceCreation( | |
718 const dbus::ObjectPath& adapter_path, | |
719 bool success) { | |
720 if (!success) | |
721 LOG(WARNING) << "CancelDeviceCreation failed: " << address_; | |
722 } | |
723 | |
724 void BluetoothDeviceChromeOS::SearchServicesForNameErrorCallback( | |
725 const ProvidesServiceCallback& callback) { | |
726 callback.Run(false); | |
727 } | |
728 | |
729 void BluetoothDeviceChromeOS::SearchServicesForNameCallback( | |
730 const std::string& name, | |
731 const ProvidesServiceCallback& callback, | |
732 const ServiceRecordList& list) { | |
733 for (ServiceRecordList::const_iterator i = list.begin(); | |
734 i != list.end(); ++i) { | |
735 if ((*i)->name() == name) { | |
736 callback.Run(true); | |
737 return; | |
738 } | |
739 } | |
740 callback.Run(false); | |
741 } | |
742 | |
743 void BluetoothDeviceChromeOS::GetServiceRecordsForConnectErrorCallback( | |
744 const SocketCallback& callback) { | |
745 callback.Run(NULL); | |
746 } | |
747 | |
748 void BluetoothDeviceChromeOS::GetServiceRecordsForConnectCallback( | |
749 const std::string& service_uuid, | |
750 const SocketCallback& callback, | |
751 const ServiceRecordList& list) { | |
752 for (ServiceRecordList::const_iterator i = list.begin(); | |
753 i != list.end(); ++i) { | |
754 if ((*i)->uuid() == service_uuid) { | |
755 // If multiple service records are found, use the first one that works. | |
756 scoped_refptr<BluetoothSocket> socket( | |
757 BluetoothSocketChromeOS::CreateBluetoothSocket(**i)); | |
758 if (socket.get() != NULL) { | |
759 callback.Run(socket); | |
760 return; | |
761 } | |
762 } | |
763 } | |
764 callback.Run(NULL); | |
765 } | |
766 | |
767 void BluetoothDeviceChromeOS::OnRemoteDataCallback( | |
768 const base::Closure& callback, | |
769 const ErrorCallback& error_callback, | |
770 bool success) { | |
771 if (success) | |
772 callback.Run(); | |
773 else | |
774 error_callback.Run(); | |
775 } | |
776 | |
777 void BluetoothDeviceChromeOS::DisconnectRequested( | |
778 const dbus::ObjectPath& object_path) { | |
779 DCHECK(object_path == object_path_); | |
780 } | |
781 | |
782 void BluetoothDeviceChromeOS::Release() { | |
783 DCHECK(agent_.get()); | |
784 VLOG(1) << "Release: " << address_; | |
785 | |
786 DCHECK(pairing_delegate_); | |
787 pairing_delegate_->DismissDisplayOrConfirm(); | |
788 pairing_delegate_ = NULL; | |
789 | |
790 pincode_callback_.Reset(); | |
791 passkey_callback_.Reset(); | |
792 confirmation_callback_.Reset(); | |
793 | |
794 agent_.reset(); | |
795 } | |
796 | |
797 void BluetoothDeviceChromeOS::RequestPinCode( | |
798 const dbus::ObjectPath& device_path, | |
799 const PinCodeCallback& callback) { | |
800 DCHECK(agent_.get()); | |
801 VLOG(1) << "RequestPinCode: " << device_path.value(); | |
802 | |
803 DCHECK(pairing_delegate_); | |
804 DCHECK(pincode_callback_.is_null()); | |
805 pincode_callback_ = callback; | |
806 pairing_delegate_->RequestPinCode(this); | |
807 } | |
808 | |
809 void BluetoothDeviceChromeOS::RequestPasskey( | |
810 const dbus::ObjectPath& device_path, | |
811 const PasskeyCallback& callback) { | |
812 DCHECK(agent_.get()); | |
813 DCHECK(device_path == object_path_); | |
814 VLOG(1) << "RequestPasskey: " << device_path.value(); | |
815 | |
816 DCHECK(pairing_delegate_); | |
817 DCHECK(passkey_callback_.is_null()); | |
818 passkey_callback_ = callback; | |
819 pairing_delegate_->RequestPasskey(this); | |
820 } | |
821 | |
822 void BluetoothDeviceChromeOS::DisplayPinCode( | |
823 const dbus::ObjectPath& device_path, | |
824 const std::string& pincode) { | |
825 DCHECK(agent_.get()); | |
826 DCHECK(device_path == object_path_); | |
827 VLOG(1) << "DisplayPinCode: " << device_path.value() << " " << pincode; | |
828 | |
829 DCHECK(pairing_delegate_); | |
830 pairing_delegate_->DisplayPinCode(this, pincode); | |
831 } | |
832 | |
833 void BluetoothDeviceChromeOS::DisplayPasskey( | |
834 const dbus::ObjectPath& device_path, | |
835 uint32 passkey) { | |
836 DCHECK(agent_.get()); | |
837 DCHECK(device_path == object_path_); | |
838 VLOG(1) << "DisplayPasskey: " << device_path.value() << " " << passkey; | |
839 | |
840 DCHECK(pairing_delegate_); | |
841 pairing_delegate_->DisplayPasskey(this, passkey); | |
842 } | |
843 | |
844 void BluetoothDeviceChromeOS::RequestConfirmation( | |
845 const dbus::ObjectPath& device_path, | |
846 uint32 passkey, | |
847 const ConfirmationCallback& callback) { | |
848 DCHECK(agent_.get()); | |
849 DCHECK(device_path == object_path_); | |
850 VLOG(1) << "RequestConfirmation: " << device_path.value() << " " << passkey; | |
851 | |
852 DCHECK(pairing_delegate_); | |
853 DCHECK(confirmation_callback_.is_null()); | |
854 confirmation_callback_ = callback; | |
855 pairing_delegate_->ConfirmPasskey(this, passkey); | |
856 } | |
857 | |
858 void BluetoothDeviceChromeOS::Authorize(const dbus::ObjectPath& device_path, | |
859 const std::string& uuid, | |
860 const ConfirmationCallback& callback) { | |
861 DCHECK(agent_.get()); | |
862 DCHECK(device_path == object_path_); | |
863 LOG(WARNING) << "Rejected authorization for service: " << uuid | |
864 << " requested from device: " << device_path.value(); | |
865 callback.Run(REJECTED); | |
866 } | |
867 | |
868 void BluetoothDeviceChromeOS::ConfirmModeChange( | |
869 Mode mode, | |
870 const ConfirmationCallback& callback) { | |
871 DCHECK(agent_.get()); | |
872 LOG(WARNING) << "Rejected adapter-level mode change: " << mode | |
873 << " made on agent for device: " << address_; | |
874 callback.Run(REJECTED); | |
875 } | |
876 | |
877 void BluetoothDeviceChromeOS::Cancel() { | |
878 DCHECK(agent_.get()); | |
879 VLOG(1) << "Cancel: " << address_; | |
880 | |
881 DCHECK(pairing_delegate_); | |
882 pairing_delegate_->DismissDisplayOrConfirm(); | |
883 } | |
884 | |
885 | |
886 // static | |
887 BluetoothDeviceChromeOS* BluetoothDeviceChromeOS::Create( | |
888 BluetoothAdapterChromeOS* adapter) { | |
889 return new BluetoothDeviceChromeOS(adapter); | |
890 } | |
891 | |
892 } // namespace chromeos | |
OLD | NEW |