1 // Copyright 2014 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.
5 #include "components/proximity_auth/bluetooth_connection_finder.h"
8 #include "base/location.h"
9 #include "base/logging.h"
10 #include "base/single_thread_task_runner.h"
11 #include "base/thread_task_runner_handle.h"
12 #include "components/proximity_auth/bluetooth_connection.h"
13 #include "components/proximity_auth/logging/logging.h"
14 #include "device/bluetooth/bluetooth_adapter_factory.h"
16 using device::BluetoothAdapter
;
18 namespace proximity_auth
{
20 BluetoothConnectionFinder::BluetoothConnectionFinder(
21 const RemoteDevice
& remote_device
,
22 const device::BluetoothUUID
& uuid
,
23 const base::TimeDelta
& polling_interval
)
24 : remote_device_(remote_device
),
26 polling_interval_(polling_interval
),
27 has_delayed_poll_scheduled_(false),
28 weak_ptr_factory_(this) {
31 BluetoothConnectionFinder::~BluetoothConnectionFinder() {
32 UnregisterAsObserver();
35 void BluetoothConnectionFinder::Find(
36 const ConnectionCallback
& connection_callback
) {
37 if (!device::BluetoothAdapterFactory::IsBluetoothAdapterAvailable()) {
38 PA_LOG(WARNING
) << "Bluetooth is unsupported on this platform. Aborting.";
42 DCHECK(start_time_
.is_null());
43 PA_LOG(WARNING
) << "Finding Bluetooth connection...";
45 start_time_
= base::TimeTicks::Now();
46 connection_callback_
= connection_callback
;
48 device::BluetoothAdapterFactory::GetAdapter(
49 base::Bind(&BluetoothConnectionFinder::OnAdapterInitialized
,
50 weak_ptr_factory_
.GetWeakPtr()));
53 scoped_ptr
<Connection
> BluetoothConnectionFinder::CreateConnection() {
54 return scoped_ptr
<Connection
>(new BluetoothConnection(remote_device_
, uuid_
));
57 void BluetoothConnectionFinder::SeekDeviceByAddress(
58 const std::string
& bluetooth_address
,
59 const base::Closure
& callback
,
60 const bluetooth_util::ErrorCallback
& error_callback
) {
61 bluetooth_util::SeekDeviceByAddress(
62 bluetooth_address
, callback
, error_callback
,
63 base::ThreadTaskRunnerHandle::Get().get());
66 bool BluetoothConnectionFinder::IsReadyToPoll() {
67 bool is_adapter_available
=
68 adapter_
.get() && adapter_
->IsPresent() && adapter_
->IsPowered();
69 PA_LOG(INFO
) << "Readiness: adapter="
70 << (is_adapter_available
? "available" : "unavailable");
71 return is_adapter_available
;
74 void BluetoothConnectionFinder::PollIfReady() {
78 // If there is a pending task to poll at a later time, the time requisite
79 // timeout has not yet elapsed since the previous polling attempt. In that
80 // case, keep waiting until the delayed task comes in.
81 if (has_delayed_poll_scheduled_
)
84 // If the |connection_| is pending, wait for it to connect or fail prior to
86 if (connection_
&& connection_
->status() != Connection::DISCONNECTED
)
89 // This SeekDeviceByAddress operation is needed to connect to a device if
90 // it is not already known to the adapter.
91 if (!adapter_
->GetDevice(remote_device_
.bluetooth_address
)) {
92 PA_LOG(INFO
) << "Remote device [" << remote_device_
.bluetooth_address
94 << "Seeking device directly by address...";
97 remote_device_
.bluetooth_address
,
98 base::Bind(&BluetoothConnectionFinder::OnSeekedDeviceByAddress
,
99 weak_ptr_factory_
.GetWeakPtr()),
100 base::Bind(&BluetoothConnectionFinder::OnSeekedDeviceByAddressError
,
101 weak_ptr_factory_
.GetWeakPtr()));
103 PA_LOG(INFO
) << "Remote device known, connecting...";
104 connection_
= CreateConnection();
105 connection_
->AddObserver(this);
106 connection_
->Connect();
110 void BluetoothConnectionFinder::PostDelayedPoll() {
111 if (has_delayed_poll_scheduled_
) {
112 PA_LOG(WARNING
) << "Delayed poll already scheduled, skipping.";
116 PA_LOG(INFO
) << "Posting delayed poll..";
117 has_delayed_poll_scheduled_
= true;
118 base::ThreadTaskRunnerHandle::Get()->PostDelayedTask(
119 FROM_HERE
, base::Bind(&BluetoothConnectionFinder::OnDelayedPoll
,
120 weak_ptr_factory_
.GetWeakPtr()),
124 void BluetoothConnectionFinder::OnDelayedPoll() {
125 // Note that there is no longer a pending task, and therefore polling is
127 has_delayed_poll_scheduled_
= false;
131 void BluetoothConnectionFinder::OnSeekedDeviceByAddress() {
132 // Sanity check that the remote device is now known by the adapter.
133 if (adapter_
->GetDevice(remote_device_
.bluetooth_address
))
139 void BluetoothConnectionFinder::OnSeekedDeviceByAddressError(
140 const std::string
& error_message
) {
141 PA_LOG(ERROR
) << "Failed to seek device: " << error_message
;
145 void BluetoothConnectionFinder::UnregisterAsObserver() {
147 connection_
->RemoveObserver(this);
148 // The connection is about to be released or destroyed, so no need to clear
149 // it explicitly here.
152 if (adapter_
.get()) {
153 adapter_
->RemoveObserver(this);
158 void BluetoothConnectionFinder::OnAdapterInitialized(
159 scoped_refptr
<BluetoothAdapter
> adapter
) {
161 adapter_
->AddObserver(this);
165 void BluetoothConnectionFinder::AdapterPresentChanged(BluetoothAdapter
* adapter
,
170 void BluetoothConnectionFinder::AdapterPoweredChanged(BluetoothAdapter
* adapter
,
175 void BluetoothConnectionFinder::OnConnectionStatusChanged(
176 Connection
* connection
,
177 Connection::Status old_status
,
178 Connection::Status new_status
) {
179 DCHECK_EQ(connection
, connection_
.get());
181 if (connection_
->IsConnected()) {
182 base::TimeDelta elapsed
= base::TimeTicks::Now() - start_time_
;
183 PA_LOG(WARNING
) << "Connection found! Elapsed Time: "
184 << elapsed
.InMilliseconds() << "ms.";
185 UnregisterAsObserver();
187 // If we invoke the callback now, the callback function may install its own
188 // observer to |connection_|. Because we are in the ConnectionObserver
189 // callstack, this new observer will receive this connection event.
190 // Therefore, we need to invoke the callback asynchronously.
191 base::ThreadTaskRunnerHandle::Get()->PostTask(
192 FROM_HERE
, base::Bind(&BluetoothConnectionFinder::InvokeCallbackAsync
,
193 weak_ptr_factory_
.GetWeakPtr()));
194 } else if (old_status
== Connection::IN_PROGRESS
) {
196 << "Connection failed! Scheduling another polling iteration.";
201 void BluetoothConnectionFinder::InvokeCallbackAsync() {
202 connection_callback_
.Run(connection_
.Pass());
205 } // namespace proximity_auth