Index: device/bluetooth/bluetooth_device_chromeos.cc |
diff --git a/device/bluetooth/bluetooth_device_chromeos.cc b/device/bluetooth/bluetooth_device_chromeos.cc |
index 996fb23a0c9b83a2e67fd57f82dcac1a7f171662..c9608203f6f1c20f44bd767d008cd12e3a19186d 100644 |
--- a/device/bluetooth/bluetooth_device_chromeos.cc |
+++ b/device/bluetooth/bluetooth_device_chromeos.cc |
@@ -46,6 +46,7 @@ BluetoothDeviceChromeOS::BluetoothDeviceChromeOS( |
adapter_(adapter), |
pairing_delegate_(NULL), |
connecting_applications_counter_(0), |
+ service_records_loaded_(false), |
weak_ptr_factory_(this) { |
} |
@@ -71,7 +72,11 @@ void BluetoothDeviceChromeOS::GetServiceRecords( |
base::Bind(&BluetoothDeviceChromeOS::CollectServiceRecordsCallback, |
weak_ptr_factory_.GetWeakPtr(), |
callback, |
- error_callback)); |
+ base::Bind( |
+ &BluetoothDeviceChromeOS::OnGetServiceRecordsError, |
+ weak_ptr_factory_.GetWeakPtr(), |
+ callback, |
+ error_callback))); |
} |
bool BluetoothDeviceChromeOS::ProvidesServiceWithUUID( |
@@ -369,14 +374,20 @@ void BluetoothDeviceChromeOS::OnCreateDevice( |
GetProperties(object_path_)->trusted.Set( |
true, |
base::Bind(&BluetoothDeviceChromeOS::OnSetTrusted, |
- weak_ptr_factory_.GetWeakPtr(), |
- callback, |
- base::Bind(error_callback, |
- ERROR_UNKNOWN))); |
- // TODO(deymo): Replace ERROR_UNKNOWN with an appropriate new constant. |
+ weak_ptr_factory_.GetWeakPtr())); |
- // Connect application-layer protocols. |
- ConnectApplications(callback, error_callback); |
+ // In parallel with the |trusted| property change, call GetServiceRecords to |
+ // retrieve the SDP from the device and then, either on success or failure, |
+ // call ConnectApplications. |
+ GetServiceRecords( |
+ base::Bind(&BluetoothDeviceChromeOS::OnInitialGetServiceRecords, |
+ weak_ptr_factory_.GetWeakPtr(), |
+ callback, |
+ error_callback), |
+ base::Bind(&BluetoothDeviceChromeOS::OnInitialGetServiceRecordsError, |
+ weak_ptr_factory_.GetWeakPtr(), |
+ callback, |
+ error_callback)); |
} |
void BluetoothDeviceChromeOS::OnCreateDeviceError( |
@@ -416,22 +427,77 @@ void BluetoothDeviceChromeOS::CollectServiceRecordsCallback( |
return; |
} |
- ScopedVector<BluetoothServiceRecord> records; |
+ // Update the cache. No other thread is executing a GetServiceRecords |
+ // callback, so it is safe to delete the previous objects here. |
+ service_records_.clear(); |
+ // TODO(deymo): Perhaps don't update the cache if the new SDP information is |
+ // empty and we had something before. Some devices only answer this |
+ // information while paired, and this callback could be called in any order if |
+ // several calls to GetServiceRecords are made while initial pairing with the |
+ // device. This requires more investigation. |
for (BluetoothDeviceClient::ServiceMap::const_iterator i = |
service_map.begin(); i != service_map.end(); ++i) { |
- records.push_back( |
+ service_records_.push_back( |
new BluetoothServiceRecordChromeOS(address(), i->second)); |
} |
- callback.Run(records); |
+ service_records_loaded_ = true; |
+ OnServiceRecordsChanged(); |
+ |
+ callback.Run(service_records_); |
+} |
+ |
+void BluetoothDeviceChromeOS::OnServiceRecordsChanged(void) { |
+ // Update the BluetoothDevice::connectable_ property. |
+ bool hid_normally_connectable = true; |
+ bool hid_reconnect_initiate = true; |
+ for (ServiceRecordList::const_iterator it = service_records_.begin(); |
+ it != service_records_.end(); ++it) { |
+ if ((*it)->SupportsHid()) { |
+ // If there are several HID profiles, we assume the device is connectable |
+ // if all them are connectable. |
+ hid_normally_connectable = |
+ hid_normally_connectable && (*it)->hid_normally_connectable(); |
+ hid_reconnect_initiate = |
+ hid_reconnect_initiate && (*it)->hid_reconnect_initiate(); |
+ } |
+ } |
+ // The Bluetooth HID spec states that if HIDNormallyConnectable or |
+ // HIDReconnectInitiate are not present in a HID profile, the value is false. |
+ // Nevertheless, a device with both properties in false can't reconnect to the |
+ // adapter and can't be reconnected from the adapter. To avoid problems with |
+ // devices that don't export this properties we asume they are connectable. |
+ connectable_ = hid_normally_connectable || !hid_reconnect_initiate; |
+ DVLOG(1) << "ServiceRecordsChanged for " << address_ |
+ << ": connectable = " << connectable_; |
} |
-void BluetoothDeviceChromeOS::OnSetTrusted(const base::Closure& callback, |
- const ErrorCallback& error_callback, |
- bool success) { |
- if (success) { |
- callback.Run(); |
+void BluetoothDeviceChromeOS::OnSetTrusted(bool success) { |
+ LOG_IF(WARNING, !success) << "Failed to set device as trusted: " << address_; |
+} |
+ |
+void BluetoothDeviceChromeOS::OnInitialGetServiceRecords( |
+ const base::Closure& callback, |
+ const ConnectErrorCallback& error_callback, |
+ const ServiceRecordList& list) { |
+ // Connect application-layer protocols. |
+ ConnectApplications(callback, error_callback); |
+} |
+ |
+void BluetoothDeviceChromeOS::OnInitialGetServiceRecordsError( |
+ const base::Closure& callback, |
+ const ConnectErrorCallback& error_callback) { |
+ // Ignore the error retrieving the service records and continue. |
+ LOG(WARNING) << "Error retrieving SDP for " << address_ << " after pairing."; |
+ // Connect application-layer protocols. |
+ ConnectApplications(callback, error_callback); |
+} |
+ |
+void BluetoothDeviceChromeOS::OnGetServiceRecordsError( |
+ const ServiceRecordsCallback& callback, |
+ const ErrorCallback& error_callback) { |
+ if (service_records_loaded_) { |
+ callback.Run(service_records_); |
} else { |
- LOG(WARNING) << "Failed to set device as trusted: " << address_; |
error_callback.Run(); |
} |
} |