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 |
new file mode 100644 |
index 0000000000000000000000000000000000000000..871276d76421bbe84d823f8e1e1a8a990709aeda |
--- /dev/null |
+++ b/components/proximity_auth/bluetooth_connection_finder.cc |
@@ -0,0 +1,157 @@ |
+// Copyright 2014 The Chromium Authors. All rights reserved. |
+// Use of this source code is governed by a BSD-style license that can be |
+// found in the LICENSE file. |
+ |
+#include "components/proximity_auth/bluetooth_connection_finder.h" |
+ |
+#include "base/bind.h" |
+#include "base/location.h" |
+#include "base/logging.h" |
+#include "base/message_loop/message_loop_proxy.h" |
+#include "components/proximity_auth/bluetooth_connection.h" |
+#include "device/bluetooth/bluetooth_adapter_factory.h" |
+ |
+using device::BluetoothAdapter; |
+ |
+namespace proximity_auth { |
+ |
+BluetoothConnectionFinder::BluetoothConnectionFinder( |
+ const RemoteDevice& remote_device, |
+ const device::BluetoothUUID& uuid, |
+ const base::TimeDelta& polling_interval) |
+ : remote_device_(remote_device), |
+ uuid_(uuid), |
+ polling_interval_(polling_interval), |
+ has_delayed_poll_scheduled_(false), |
+ weak_ptr_factory_(this) { |
+} |
+ |
+BluetoothConnectionFinder::~BluetoothConnectionFinder() { |
+ UnregisterAsObserver(); |
+} |
+ |
+void BluetoothConnectionFinder::Find( |
+ const ConnectionCallback& connection_callback) { |
+ if (!device::BluetoothAdapterFactory::IsBluetoothAdapterAvailable()) { |
+ VLOG(1) << "[BCF] Bluetooth is unsupported on this platform. Aborting."; |
+ return; |
+ } |
+ |
+ DCHECK(start_time_.is_null()); |
+ VLOG(1) << "[BCF] Finding Bluetooth connection..."; |
+ |
+ start_time_ = base::TimeTicks::Now(); |
+ connection_callback_ = connection_callback; |
+ |
+ // TODO(isherman): Register as an observer of screen lock changes. |
+ |
+ device::BluetoothAdapterFactory::GetAdapter( |
+ base::Bind(&BluetoothConnectionFinder::OnAdapterInitialized, |
+ weak_ptr_factory_.GetWeakPtr())); |
+} |
+ |
+scoped_ptr<Connection> BluetoothConnectionFinder::CreateConnection() { |
+ return scoped_ptr<Connection>(new BluetoothConnection(remote_device_, uuid_)); |
+} |
+ |
+bool BluetoothConnectionFinder::IsReadyToPoll() { |
+ bool is_adapter_available = |
+ adapter_.get() && adapter_->IsPresent() && adapter_->IsPowered(); |
+ // TODO(isherman): Determine the screen locked state for really reals. |
+ bool is_screen_locked = true; |
+ VLOG(1) << "[BCF] Readiness: adapter=" |
+ << (is_adapter_available ? "available" : "unavailable") |
+ << ", screen=" << (is_screen_locked ? "locked" : "unlocked"); |
+ return is_adapter_available && is_screen_locked; |
+} |
+ |
+void BluetoothConnectionFinder::PollIfReady() { |
+ if (!IsReadyToPoll()) |
+ return; |
+ |
+ // If there is a pending task to poll at a later time, the time requisite |
+ // timeout has not yet elapsed since the previous polling attempt. In that |
+ // case, keep waiting until the delayed task comes in. |
+ if (has_delayed_poll_scheduled_) |
+ return; |
+ |
+ // If the |connection_| exists, wait for it to connect or fail prior to |
+ // polling again. |
+ if (connection_) |
+ return; |
+ |
+ VLOG(1) << "[BCF] Polling for connection..."; |
+ connection_ = CreateConnection(); |
+ connection_->AddObserver(this); |
+ connection_->Connect(); |
+} |
+ |
+void BluetoothConnectionFinder::DelayedPollIfReady() { |
+ // Note that there is no longer a pending task, and therefore polling is |
+ // permitted. |
+ has_delayed_poll_scheduled_ = false; |
+ PollIfReady(); |
+} |
+ |
+void BluetoothConnectionFinder::UnregisterAsObserver() { |
+ if (connection_) { |
+ connection_->RemoveObserver(this); |
+ // The connection is about to be released or destroyed, so no need to clear |
+ // it explicitly here. |
+ } |
+ |
+ if (adapter_.get()) { |
+ adapter_->RemoveObserver(this); |
+ adapter_ = NULL; |
+ } |
+ |
+ // TODO(isherman): Unregister as screen lock observer as well. |
+} |
+ |
+void BluetoothConnectionFinder::OnAdapterInitialized( |
+ scoped_refptr<BluetoothAdapter> adapter) { |
+ adapter_ = adapter; |
+ adapter_->AddObserver(this); |
+ PollIfReady(); |
+} |
+ |
+void BluetoothConnectionFinder::AdapterPresentChanged(BluetoothAdapter* adapter, |
+ bool present) { |
+ PollIfReady(); |
+} |
+ |
+void BluetoothConnectionFinder::AdapterPoweredChanged(BluetoothAdapter* adapter, |
+ bool powered) { |
+ PollIfReady(); |
+} |
+ |
+// TODO(isherman): Wire this up. |
+void BluetoothConnectionFinder::OnScreenLockStateChanged() { |
+ PollIfReady(); |
+} |
+ |
+void BluetoothConnectionFinder::OnConnectionStatusChanged( |
+ const Connection& connection, |
+ Connection::Status old_status, |
+ Connection::Status new_status) { |
+ DCHECK_EQ(&connection, connection_.get()); |
+ |
+ if (connection_->IsConnected()) { |
+ base::TimeDelta elapsed = base::TimeTicks::Now() - start_time_; |
+ VLOG(1) << "[BCF] Connection found! Elapsed Time: " |
+ << elapsed.InMilliseconds() << "ms."; |
+ UnregisterAsObserver(); |
+ connection_callback_.Run(connection_.Pass()); |
+ } else if (old_status == Connection::IN_PROGRESS) { |
+ VLOG(1) << "[BCF] Connection failed! Scheduling another polling iteration."; |
+ connection_.reset(); |
+ has_delayed_poll_scheduled_ = true; |
+ base::MessageLoopProxy::current()->PostDelayedTask( |
+ FROM_HERE, |
+ base::Bind(&BluetoothConnectionFinder::DelayedPollIfReady, |
+ weak_ptr_factory_.GetWeakPtr()), |
+ polling_interval_); |
+ } |
+} |
+ |
+} // namespace proximity_auth |