Skip to content

Commit

Permalink
[CrOS Bluetooth] Add automatic pairing to BluetoothHidDetectorImpl.
Browse files Browse the repository at this point in the history
Update BluetoothHidDetectorImpl to queue discovered devices when
Bluetooth HID detection starts and attempt to pair with them
consecutively. Adding BluetoothHidDetectorDelegate and notifying the
delegate when the Bluetooth HID detection status changes will be added
in a follow-up CL.

Bug: 1299099
Test: BluetoothHidDetectorImplTest
Change-Id: I0cff676e6278ab9b10a3b0376d4e79432b1ea67a
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/3576779
Reviewed-by: Chad Duffin <chadduffin@chromium.org>
Commit-Queue: Gordon Seto <gordonseto@google.com>
Cr-Commit-Position: refs/heads/main@{#990659}
  • Loading branch information
Gordon Seto authored and Chromium LUCI CQ committed Apr 8, 2022
1 parent e2d1777 commit 81cb41c
Show file tree
Hide file tree
Showing 8 changed files with 445 additions and 23 deletions.
8 changes: 7 additions & 1 deletion ash/components/hid_detection/bluetooth_hid_detector.h
Expand Up @@ -13,9 +13,15 @@ namespace hid_detection {
// currently paired with.
class BluetoothHidDetector {
public:
struct InputDevicesStatus {
bool pointer_is_missing;
bool keyboard_is_missing;
};

virtual ~BluetoothHidDetector();

virtual void StartBluetoothHidDetection() = 0;
virtual void StartBluetoothHidDetection(
InputDevicesStatus input_devices_status) = 0;
virtual void StopBluetoothHidDetection() = 0;

protected:
Expand Down
146 changes: 136 additions & 10 deletions ash/components/hid_detection/bluetooth_hid_detector_impl.cc
Expand Up @@ -6,10 +6,14 @@
#include "ash/public/cpp/bluetooth_config_service.h"
#include "components/device_event_log/device_event_log.h"

using chromeos::bluetooth_config::mojom::BluetoothSystemState;

namespace ash {
namespace hid_detection {
namespace {
using chromeos::bluetooth_config::mojom::BluetoothDevicePropertiesPtr;
using chromeos::bluetooth_config::mojom::BluetoothSystemState;
using chromeos::bluetooth_config::mojom::DeviceType;
using chromeos::bluetooth_config::mojom::KeyEnteredHandler;
} // namespace

BluetoothHidDetectorImpl::BluetoothHidDetectorImpl() = default;

Expand All @@ -18,9 +22,15 @@ BluetoothHidDetectorImpl::~BluetoothHidDetectorImpl() {
<< "BluetoothHidDetectorImpl is destroyed.";
}

void BluetoothHidDetectorImpl::StartBluetoothHidDetection() {
void BluetoothHidDetectorImpl::StartBluetoothHidDetection(
InputDevicesStatus input_devices_status) {
DCHECK(input_devices_status.pointer_is_missing ||
input_devices_status.keyboard_is_missing)
<< "StartBluetoothHidDetection() called when neither pointer or keyboard "
<< "is missing";
DCHECK_EQ(kNotStarted, state_);
HID_LOG(EVENT) << "Starting Bluetooth HID detection";
input_devices_status_ = input_devices_status;
state_ = kStarting;
GetBluetoothConfigService(
cros_bluetooth_config_remote_.BindNewPipeAndPassReceiver());
Expand All @@ -36,7 +46,7 @@ void BluetoothHidDetectorImpl::StopBluetoothHidDetection() {
cros_bluetooth_config_remote_->SetBluetoothHidDetectionActive(false);
cros_bluetooth_config_remote_.reset();
system_properties_observer_receiver_.reset();
bluetooth_discovery_delegate_receiver_.reset();
ResetDiscoveryState();
}

void BluetoothHidDetectorImpl::OnPropertiesUpdated(
Expand Down Expand Up @@ -80,7 +90,6 @@ void BluetoothHidDetectorImpl::OnPropertiesUpdated(
HID_LOG(EVENT) << "Bluetooth adapter has stopped being enabled while "
<< "Bluetooth HID detection is in progress";
state_ = kStoppedExternally;
bluetooth_discovery_delegate_receiver_.reset();
}
return;
case kStoppedExternally:
Expand All @@ -98,15 +107,132 @@ void BluetoothHidDetectorImpl::OnPropertiesUpdated(
void BluetoothHidDetectorImpl::OnBluetoothDiscoveryStarted(
mojo::PendingRemote<chromeos::bluetooth_config::mojom::DevicePairingHandler>
handler) {
// TODO(crbug.com/1299099): Implement pairing.
HID_LOG(EVENT) << "Bluetooth discovery started.";
DCHECK(!device_pairing_handler_remote_);
device_pairing_handler_remote_.Bind(std::move(handler));
}

void BluetoothHidDetectorImpl::OnBluetoothDiscoveryStopped() {}
void BluetoothHidDetectorImpl::OnBluetoothDiscoveryStopped() {
HID_LOG(EVENT) << "Bluetooth discovery stopped.";
ResetDiscoveryState();
}

void BluetoothHidDetectorImpl::OnDiscoveredDevicesListChanged(
std::vector<chromeos::bluetooth_config::mojom::BluetoothDevicePropertiesPtr>
discovered_devices) {
// TODO(crbug.com/1299099): Implement pairing.
std::vector<BluetoothDevicePropertiesPtr> discovered_devices) {
for (const auto& discovered_device : discovered_devices) {
if (!ShouldAttemptToPairWithDevice(discovered_device))
continue;
if (queued_device_ids_.contains(discovered_device->id))
continue;

queued_device_ids_.insert(discovered_device->id);
queue_->emplace(discovered_device.Clone());
HID_LOG(EVENT) << "Queuing device: " << discovered_device->id << ". ["
<< queue_->size() << "] devices now in queue.";
}
ProcessQueue();
}

void BluetoothHidDetectorImpl::RequestPinCode(RequestPinCodeCallback callback) {
// TODO(crbug/1299099): Implement.
}

void BluetoothHidDetectorImpl::RequestPasskey(RequestPasskeyCallback callback) {
// TODO(crbug/1299099): Implement.
}

void BluetoothHidDetectorImpl::DisplayPinCode(
const std::string& pin_code,
mojo::PendingReceiver<KeyEnteredHandler> handler) {
// TODO(crbug/1299099): Implement.
}

void BluetoothHidDetectorImpl::DisplayPasskey(
const std::string& passkey,
mojo::PendingReceiver<KeyEnteredHandler> handler) {
// TODO(crbug/1299099): Implement.
}

void BluetoothHidDetectorImpl::ConfirmPasskey(const std::string& passkey,
ConfirmPasskeyCallback callback) {
// TODO(crbug/1299099): Implement.
}

void BluetoothHidDetectorImpl::AuthorizePairing(
AuthorizePairingCallback callback) {
// TODO(crbug/1299099): Implement.
}

bool BluetoothHidDetectorImpl::ShouldAttemptToPairWithDevice(
const BluetoothDevicePropertiesPtr& device) {
switch (device->device_type) {
case DeviceType::kMouse:
[[fallthrough]];
case DeviceType::kTablet:
return input_devices_status_.pointer_is_missing;
case DeviceType::kKeyboard:
return input_devices_status_.keyboard_is_missing;
case DeviceType::kKeyboardMouseCombo:
return input_devices_status_.pointer_is_missing ||
input_devices_status_.keyboard_is_missing;
default:
return false;
}
}

void BluetoothHidDetectorImpl::ProcessQueue() {
if (current_pairing_device_)
return;

if (queue_->empty()) {
HID_LOG(DEBUG) << "No devices queued";
return;
}

current_pairing_device_ = std::move(queue_->front());
queue_->pop();
HID_LOG(EVENT) << "Popped device with id: "
<< current_pairing_device_.value()->id
<< " from front of queue. [" << queue_->size()
<< "] devices now in queue.";

// TODO(crbug.com/1299099): Check if device type is still missing and return
// early if not.

// TODO(crbug.com/1299099): Notify delegate of change in status.
HID_LOG(EVENT) << "Pairing with device with id: "
<< current_pairing_device_.value()->id;
device_pairing_handler_remote_->PairDevice(
current_pairing_device_.value()->id,
device_pairing_delegate_receiver_.BindNewPipeAndPassRemote(),
base::BindOnce(&BluetoothHidDetectorImpl::OnPairDevice,
weak_ptr_factory_.GetWeakPtr()));
}

void BluetoothHidDetectorImpl::OnPairDevice(
chromeos::bluetooth_config::mojom::PairingResult pairing_result) {
// TODO(crbug.com/1299099): Notify delegate of change in status.
HID_LOG(EVENT) << "Finished pairing with "
<< current_pairing_device_.value()->id
<< ", result: " << pairing_result << ", [" << queue_->size()
<< "] devices still in queue.";
queued_device_ids_.erase(current_pairing_device_.value()->id);
current_pairing_device_.reset();
device_pairing_delegate_receiver_.reset();
ProcessQueue();
}

void BluetoothHidDetectorImpl::ResetDiscoveryState() {
// Reset Mojo-related properties.
bluetooth_discovery_delegate_receiver_.reset();
device_pairing_handler_remote_.reset();
device_pairing_delegate_receiver_.reset();

// Reset queue-related properties.
current_pairing_device_.reset();
queue_ = std::make_unique<base::queue<
chromeos::bluetooth_config::mojom::BluetoothDevicePropertiesPtr>>();
queued_device_ids_.clear();
}

} // namespace hid_detection
Expand Down
56 changes: 54 additions & 2 deletions ash/components/hid_detection/bluetooth_hid_detector_impl.h
Expand Up @@ -6,6 +6,9 @@
#define ASH_COMPONENTS_HID_DETECTION_BLUETOOTH_HID_DETECTOR_IMPL_H_

#include "ash/components/hid_detection/bluetooth_hid_detector.h"
#include "base/containers/flat_set.h"
#include "base/containers/queue.h"
#include "base/memory/weak_ptr.h"
#include "chromeos/services/bluetooth_config/public/mojom/cros_bluetooth_config.mojom.h"
#include "mojo/public/cpp/bindings/receiver.h"
#include "mojo/public/cpp/bindings/remote.h"
Expand All @@ -17,13 +20,15 @@ namespace hid_detection {
class BluetoothHidDetectorImpl
: public BluetoothHidDetector,
public chromeos::bluetooth_config::mojom::SystemPropertiesObserver,
public chromeos::bluetooth_config::mojom::BluetoothDiscoveryDelegate {
public chromeos::bluetooth_config::mojom::BluetoothDiscoveryDelegate,
public chromeos::bluetooth_config::mojom::DevicePairingDelegate {
public:
BluetoothHidDetectorImpl();
~BluetoothHidDetectorImpl() override;

// BluetoothHidDetector:
void StartBluetoothHidDetection() override;
void StartBluetoothHidDetection(
InputDevicesStatus input_devices_status) override;
void StopBluetoothHidDetection() override;

private:
Expand Down Expand Up @@ -63,6 +68,47 @@ class BluetoothHidDetectorImpl
chromeos::bluetooth_config::mojom::BluetoothDevicePropertiesPtr>
discovered_devices) override;

// mojom::DevicePairingDelegate:
void RequestPinCode(RequestPinCodeCallback callback) override;
void RequestPasskey(RequestPasskeyCallback callback) override;
void DisplayPinCode(const std::string& pin_code,
mojo::PendingReceiver<
chromeos::bluetooth_config::mojom::KeyEnteredHandler>
handler) override;
void DisplayPasskey(const std::string& passkey,
mojo::PendingReceiver<
chromeos::bluetooth_config::mojom::KeyEnteredHandler>
handler) override;
void ConfirmPasskey(const std::string& passkey,
ConfirmPasskeyCallback callback) override;
void AuthorizePairing(AuthorizePairingCallback callback) override;

bool ShouldAttemptToPairWithDevice(
const chromeos::bluetooth_config::mojom::BluetoothDevicePropertiesPtr&
device);

void ProcessQueue();
void OnPairDevice(
chromeos::bluetooth_config::mojom::PairingResult pairing_result);

// Resets properties related to discovery, pairing handlers and queueing.
void ResetDiscoveryState();

// Map that contains the ids of the devices in |queue_|.
base::flat_set<std::string> queued_device_ids_;

// The queue of devices that will be attempted to be paired with.
std::unique_ptr<base::queue<
chromeos::bluetooth_config::mojom::BluetoothDevicePropertiesPtr>>
queue_ = std::make_unique<base::queue<
chromeos::bluetooth_config::mojom::BluetoothDevicePropertiesPtr>>();

// The device currently being paired with.
absl::optional<
chromeos::bluetooth_config::mojom::BluetoothDevicePropertiesPtr>
current_pairing_device_;

InputDevicesStatus input_devices_status_;
State state_ = kNotStarted;

mojo::Remote<chromeos::bluetooth_config::mojom::CrosBluetoothConfig>
Expand All @@ -71,6 +117,12 @@ class BluetoothHidDetectorImpl
system_properties_observer_receiver_{this};
mojo::Receiver<chromeos::bluetooth_config::mojom::BluetoothDiscoveryDelegate>
bluetooth_discovery_delegate_receiver_{this};
mojo::Remote<chromeos::bluetooth_config::mojom::DevicePairingHandler>
device_pairing_handler_remote_;
mojo::Receiver<chromeos::bluetooth_config::mojom::DevicePairingDelegate>
device_pairing_delegate_receiver_{this};

base::WeakPtrFactory<BluetoothHidDetectorImpl> weak_ptr_factory_{this};
};

} // namespace hid_detection
Expand Down

0 comments on commit 81cb41c

Please sign in to comment.