1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145
|
// 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;
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();
VLOG(1) << "[BCF] Readiness: adapter="
<< (is_adapter_available ? "available" : "unavailable");
return is_adapter_available;
}
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;
}
}
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();
}
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
|