Index: components/proximity_auth/bluetooth_connection_finder.cc |
diff --git a/components/proximity_auth/bluetooth_connection_finder.cc b/components/proximity_auth/bluetooth_connection_finder.cc |
index 7596a11c04f49bd9aa4d9c1df65a1ead3badd37d..00b51462e767262cab80600e2ca2b9423c0fdac5 100644 |
--- a/components/proximity_auth/bluetooth_connection_finder.cc |
+++ b/components/proximity_auth/bluetooth_connection_finder.cc |
@@ -54,6 +54,15 @@ scoped_ptr<Connection> BluetoothConnectionFinder::CreateConnection() { |
return scoped_ptr<Connection>(new BluetoothConnection(remote_device_, uuid_)); |
} |
+void BluetoothConnectionFinder::SeekDeviceByAddress( |
+ const std::string& bluetooth_address, |
+ const base::Closure& callback, |
+ const bluetooth_util::ErrorCallback& error_callback) { |
+ bluetooth_util::SeekDeviceByAddress( |
+ bluetooth_address, callback, error_callback, |
+ base::ThreadTaskRunnerHandle::Get().get()); |
+} |
+ |
bool BluetoothConnectionFinder::IsReadyToPoll() { |
bool is_adapter_available = |
adapter_.get() && adapter_->IsPresent() && adapter_->IsPowered(); |
@@ -77,19 +86,62 @@ void BluetoothConnectionFinder::PollIfReady() { |
if (connection_) |
return; |
- PA_LOG(INFO) << "Polling for connection..."; |
- connection_ = CreateConnection(); |
- connection_->AddObserver(this); |
- connection_->Connect(); |
+ // This SeekDeviceByAddress operation is needed to connect to a device if |
+ // it is not already known to the adapter. |
+ if (!adapter_->GetDevice(remote_device_.bluetooth_address)) { |
+ PA_LOG(INFO) << "Remote device [" << remote_device_.bluetooth_address |
+ << "] is not known. " |
+ << "Seeking device directly by address..."; |
+ |
+ SeekDeviceByAddress( |
+ remote_device_.bluetooth_address, |
+ base::Bind(&BluetoothConnectionFinder::OnSeekedDeviceByAddress, |
+ weak_ptr_factory_.GetWeakPtr()), |
+ base::Bind(&BluetoothConnectionFinder::OnSeekedDeviceByAddressError, |
+ weak_ptr_factory_.GetWeakPtr())); |
+ } else { |
+ PA_LOG(INFO) << "Remote device known, connecting..."; |
+ connection_ = CreateConnection(); |
+ connection_->AddObserver(this); |
+ connection_->Connect(); |
+ } |
+} |
+ |
+void BluetoothConnectionFinder::PostDelayedPoll() { |
+ if (has_delayed_poll_scheduled_) { |
+ PA_LOG(WARNING) << "Delayed poll already scheduled, skipping."; |
+ return; |
+ } |
+ |
+ PA_LOG(INFO) << "Posting delayed poll.."; |
+ has_delayed_poll_scheduled_ = true; |
+ base::ThreadTaskRunnerHandle::Get()->PostDelayedTask( |
+ FROM_HERE, base::Bind(&BluetoothConnectionFinder::OnDelayedPoll, |
+ weak_ptr_factory_.GetWeakPtr()), |
+ polling_interval_); |
} |
-void BluetoothConnectionFinder::DelayedPollIfReady() { |
+void BluetoothConnectionFinder::OnDelayedPoll() { |
// Note that there is no longer a pending task, and therefore polling is |
// permitted. |
has_delayed_poll_scheduled_ = false; |
PollIfReady(); |
} |
+void BluetoothConnectionFinder::OnSeekedDeviceByAddress() { |
+ // Sanity check that the remote device is now known by the adapter. |
+ if (adapter_->GetDevice(remote_device_.bluetooth_address)) |
+ PollIfReady(); |
+ else |
+ PostDelayedPoll(); |
+} |
+ |
+void BluetoothConnectionFinder::OnSeekedDeviceByAddressError( |
+ const std::string& error_message) { |
+ PA_LOG(ERROR) << "Failed to seek device: " << error_message; |
+ PostDelayedPoll(); |
+} |
+ |
void BluetoothConnectionFinder::UnregisterAsObserver() { |
if (connection_) { |
connection_->RemoveObserver(this); |
@@ -131,17 +183,24 @@ void BluetoothConnectionFinder::OnConnectionStatusChanged( |
PA_LOG(WARNING) << "Connection found! Elapsed Time: " |
<< elapsed.InMilliseconds() << "ms."; |
UnregisterAsObserver(); |
- connection_callback_.Run(connection_.Pass()); |
+ |
+ // If we invoke the callback now, the callback function may install its own |
+ // observer to |connection_|. Because we are in the ConnectionObserver |
+ // callstack, this new observer will receive this connection event. |
+ // Therefore, we need to invoke the callback asynchronously. |
+ base::ThreadTaskRunnerHandle::Get()->PostTask( |
+ FROM_HERE, base::Bind(&BluetoothConnectionFinder::InvokeCallbackAsync, |
+ weak_ptr_factory_.GetWeakPtr())); |
} else if (old_status == Connection::IN_PROGRESS) { |
PA_LOG(WARNING) |
<< "Connection failed! Scheduling another polling iteration."; |
connection_.reset(); |
- has_delayed_poll_scheduled_ = true; |
- base::ThreadTaskRunnerHandle::Get()->PostDelayedTask( |
- FROM_HERE, base::Bind(&BluetoothConnectionFinder::DelayedPollIfReady, |
- weak_ptr_factory_.GetWeakPtr()), |
- polling_interval_); |
+ PostDelayedPoll(); |
} |
} |
+void BluetoothConnectionFinder::InvokeCallbackAsync() { |
+ connection_callback_.Run(connection_.Pass()); |
+} |
+ |
} // namespace proximity_auth |