-
Notifications
You must be signed in to change notification settings - Fork 6.6k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
This class is responsible for caching known paired Bluetooth devices so that they can be returned by the CrosBluetoothConfig API. This class is named DeviceCache instead of PairedDeviceCache because future CLs will also utilize this class for the pairing flow, which deals with unpaired devices. This CL does not instantiate DeviceCache; a follow-up CL instantiates it and uses it to return device metadata to clients. Bug: 1010321 Change-Id: I9fdb72e776fa941533a5448721f4f01e3c693097 Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/3070213 Reviewed-by: Gordon Seto <gordonseto@google.com> Reviewed-by: Tom Sepez <tsepez@chromium.org> Commit-Queue: Kyle Horimoto <khorimoto@chromium.org> Cr-Commit-Position: refs/heads/master@{#909022}
- Loading branch information
Kyle Horimoto
authored and
Chromium LUCI CQ
committed
Aug 5, 2021
1 parent
87544d9
commit 3cd0707
Showing
9 changed files
with
730 additions
and
7 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,51 @@ | ||
// Copyright 2021 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 "chromeos/services/bluetooth_config/device_cache.h" | ||
|
||
#include "chromeos/services/bluetooth_config/adapter_state_controller.h" | ||
|
||
namespace chromeos { | ||
namespace bluetooth_config { | ||
|
||
DeviceCache::DeviceCache(AdapterStateController* adapter_state_controller) | ||
: adapter_state_controller_(adapter_state_controller) {} | ||
|
||
DeviceCache::~DeviceCache() = default; | ||
|
||
std::vector<mojom::PairedBluetoothDevicePropertiesPtr> | ||
DeviceCache::GetPairedDevices() const { | ||
// If Bluetooth is not enabled or enabling, return an empty list. This | ||
// addresses an edge case: when the user disables Bluetooth, there is a short | ||
// amount of time in which Bluetooth is still enabled but is in the process of | ||
// turning off. We should still return an empty list in this case to ensure | ||
// that the UI does not show a list of devices when the toggle is off. | ||
if (!IsBluetoothEnabledOrEnabling()) | ||
return {}; | ||
|
||
return PerformGetPairedDevices(); | ||
} | ||
|
||
void DeviceCache::AddObserver(Observer* observer) { | ||
observers_.AddObserver(observer); | ||
} | ||
|
||
void DeviceCache::RemoveObserver(Observer* observer) { | ||
observers_.RemoveObserver(observer); | ||
} | ||
|
||
void DeviceCache::NotifyPairedDevicesListChanged() { | ||
for (auto& observer : observers_) | ||
observer.OnPairedDevicesListChanged(); | ||
} | ||
|
||
bool DeviceCache::IsBluetoothEnabledOrEnabling() const { | ||
const mojom::BluetoothSystemState adapter_state = | ||
adapter_state_controller_->GetAdapterState(); | ||
return adapter_state == mojom::BluetoothSystemState::kEnabled || | ||
adapter_state == mojom::BluetoothSystemState::kEnabling; | ||
} | ||
|
||
} // namespace bluetooth_config | ||
} // namespace chromeos |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,70 @@ | ||
// Copyright 2021 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. | ||
|
||
#ifndef CHROMEOS_SERVICES_BLUETOOTH_CONFIG_DEVICE_CACHE_H_ | ||
#define CHROMEOS_SERVICES_BLUETOOTH_CONFIG_DEVICE_CACHE_H_ | ||
|
||
#include <vector> | ||
|
||
#include "chromeos/services/bluetooth_config/public/mojom/cros_bluetooth_config.mojom.h" | ||
|
||
namespace chromeos { | ||
namespace bluetooth_config { | ||
|
||
class AdapterStateController; | ||
|
||
// Caches known Bluetooth devices, providing getters and an observer interface | ||
// for receiving updates when devices change. | ||
// | ||
// TODO(khorimoto): Also add support for tracking non-paired devices. | ||
class DeviceCache { | ||
public: | ||
class Observer : public base::CheckedObserver { | ||
public: | ||
~Observer() override = default; | ||
|
||
// Invoked when the list of paired devices has changed. This callback is | ||
// used when a device has been added/removed from the list, or when one or | ||
// more properties of a device in the list has changed. | ||
virtual void OnPairedDevicesListChanged() = 0; | ||
}; | ||
|
||
virtual ~DeviceCache(); | ||
|
||
// Returns a sorted list of all paired devices. The list is sorted such that | ||
// connected devices appear before connecting devices, which appear before | ||
// disconnected devices. If Bluetooth is disabled, disabling, or unavailable, | ||
// this function returns an empty list. | ||
std::vector<mojom::PairedBluetoothDevicePropertiesPtr> GetPairedDevices() | ||
const; | ||
|
||
void AddObserver(Observer* observer); | ||
void RemoveObserver(Observer* observer); | ||
|
||
protected: | ||
DeviceCache(AdapterStateController* adapter_state_controller); | ||
|
||
// Implementation-specific version of GetPairedDevices(), which is invoked | ||
// only if Bluetooth is enabled or enabling. | ||
virtual std::vector<mojom::PairedBluetoothDevicePropertiesPtr> | ||
PerformGetPairedDevices() const = 0; | ||
|
||
AdapterStateController* adapter_state_controller() { | ||
return adapter_state_controller_; | ||
} | ||
|
||
void NotifyPairedDevicesListChanged(); | ||
|
||
private: | ||
bool IsBluetoothEnabledOrEnabling() const; | ||
|
||
AdapterStateController* adapter_state_controller_; | ||
|
||
base::ObserverList<Observer> observers_; | ||
}; | ||
|
||
} // namespace bluetooth_config | ||
} // namespace chromeos | ||
|
||
#endif // CHROMEOS_SERVICES_BLUETOOTH_CONFIG_DEVICE_CACHE_H_ |
144 changes: 144 additions & 0 deletions
144
chromeos/services/bluetooth_config/device_cache_impl.cc
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,144 @@ | ||
// Copyright 2021 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 "chromeos/services/bluetooth_config/device_cache_impl.h" | ||
|
||
#include <algorithm> | ||
|
||
#include "chromeos/services/bluetooth_config/device_conversion_util.h" | ||
|
||
namespace chromeos { | ||
namespace bluetooth_config { | ||
namespace { | ||
|
||
mojom::PairedBluetoothDevicePropertiesPtr | ||
GeneratePairedBluetoothDeviceProperties(const device::BluetoothDevice* device) { | ||
mojom::PairedBluetoothDevicePropertiesPtr properties = | ||
mojom::PairedBluetoothDeviceProperties::New(); | ||
properties->device_properties = GenerateBluetoothDeviceMojoProperties(device); | ||
// TODO(khorimoto): Add paired device nickname property. | ||
return properties; | ||
} | ||
|
||
} // namespace | ||
|
||
DeviceCacheImpl::DeviceCacheImpl( | ||
AdapterStateController* adapter_state_controller_param, | ||
scoped_refptr<device::BluetoothAdapter> bluetooth_adapter) | ||
: DeviceCache(adapter_state_controller_param), | ||
bluetooth_adapter_(std::move(bluetooth_adapter)) { | ||
adapter_state_controller_observation_.Observe(adapter_state_controller()); | ||
adapter_observation_.Observe(bluetooth_adapter_.get()); | ||
|
||
FetchInitialPairedDeviceList(); | ||
} | ||
|
||
DeviceCacheImpl::~DeviceCacheImpl() = default; | ||
|
||
std::vector<mojom::PairedBluetoothDevicePropertiesPtr> | ||
DeviceCacheImpl::PerformGetPairedDevices() const { | ||
std::vector<mojom::PairedBluetoothDevicePropertiesPtr> paired_devices; | ||
for (const auto& paired_device : paired_devices_) | ||
paired_devices.push_back(paired_device.Clone()); | ||
return paired_devices; | ||
} | ||
|
||
void DeviceCacheImpl::OnAdapterStateChanged() { | ||
NotifyPairedDevicesListChanged(); | ||
} | ||
|
||
void DeviceCacheImpl::DeviceAdded(device::BluetoothAdapter* adapter, | ||
device::BluetoothDevice* device) { | ||
AttemptSetDeviceInPairedDeviceList(device); | ||
} | ||
|
||
void DeviceCacheImpl::DeviceRemoved(device::BluetoothAdapter* adapter, | ||
device::BluetoothDevice* device) { | ||
RemoveFromPairedDeviceList(device); | ||
} | ||
|
||
void DeviceCacheImpl::DeviceChanged(device::BluetoothAdapter* adapter, | ||
device::BluetoothDevice* device) { | ||
AttemptUpdatePairedDeviceMetadata(device); | ||
} | ||
|
||
void DeviceCacheImpl::DevicePairedChanged(device::BluetoothAdapter* adapter, | ||
device::BluetoothDevice* device, | ||
bool new_paired_status) { | ||
if (new_paired_status) | ||
AttemptUpdatePairedDeviceMetadata(device); | ||
else | ||
RemoveFromPairedDeviceList(device); | ||
} | ||
|
||
void DeviceCacheImpl::DeviceConnectedStateChanged( | ||
device::BluetoothAdapter* adapter, | ||
device::BluetoothDevice* device, | ||
bool is_now_connected) { | ||
AttemptUpdatePairedDeviceMetadata(device); | ||
} | ||
|
||
void DeviceCacheImpl::DeviceBatteryChanged( | ||
device::BluetoothAdapter* adapter, | ||
device::BluetoothDevice* device, | ||
absl::optional<uint8_t> new_battery_percentage) { | ||
AttemptUpdatePairedDeviceMetadata(device); | ||
} | ||
|
||
void DeviceCacheImpl::FetchInitialPairedDeviceList() { | ||
for (const device::BluetoothDevice* device : | ||
bluetooth_adapter_->GetDevices()) { | ||
paired_devices_.push_back(GeneratePairedBluetoothDeviceProperties(device)); | ||
} | ||
|
||
SortPairedDeviceList(); | ||
} | ||
|
||
void DeviceCacheImpl::AttemptSetDeviceInPairedDeviceList( | ||
device::BluetoothDevice* device) { | ||
if (!device->IsPaired()) | ||
return; | ||
|
||
// Remove the old (stale) properties, if they exist. | ||
RemoveFromPairedDeviceList(device); | ||
|
||
paired_devices_.push_back(GeneratePairedBluetoothDeviceProperties(device)); | ||
SortPairedDeviceList(); | ||
NotifyPairedDevicesListChanged(); | ||
} | ||
|
||
void DeviceCacheImpl::RemoveFromPairedDeviceList( | ||
device::BluetoothDevice* device) { | ||
auto it = paired_devices_.begin(); | ||
while (it != paired_devices_.end()) { | ||
if (device->GetIdentifier() == (*it)->device_properties->id) { | ||
paired_devices_.erase(it); | ||
NotifyPairedDevicesListChanged(); | ||
return; | ||
} | ||
|
||
++it; | ||
} | ||
} | ||
|
||
void DeviceCacheImpl::AttemptUpdatePairedDeviceMetadata( | ||
device::BluetoothDevice* device) { | ||
// Remove existing metadata about |device|. | ||
RemoveFromPairedDeviceList(device); | ||
|
||
// Now, add updated metadata. | ||
AttemptSetDeviceInPairedDeviceList(device); | ||
} | ||
|
||
void DeviceCacheImpl::SortPairedDeviceList() { | ||
std::sort(paired_devices_.begin(), paired_devices_.end(), | ||
[](const mojom::PairedBluetoothDevicePropertiesPtr& first, | ||
const mojom::PairedBluetoothDevicePropertiesPtr& second) { | ||
return first->device_properties->connection_state > | ||
second->device_properties->connection_state; | ||
}); | ||
} | ||
|
||
} // namespace bluetooth_config | ||
} // namespace chromeos |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,98 @@ | ||
// Copyright 2021 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. | ||
|
||
#ifndef CHROMEOS_SERVICES_BLUETOOTH_CONFIG_DEVICE_CACHE_IMPL_H_ | ||
#define CHROMEOS_SERVICES_BLUETOOTH_CONFIG_DEVICE_CACHE_IMPL_H_ | ||
|
||
#include "base/memory/ref_counted.h" | ||
#include "base/scoped_observation.h" | ||
#include "chromeos/services/bluetooth_config/adapter_state_controller.h" | ||
#include "chromeos/services/bluetooth_config/device_cache.h" | ||
#include "chromeos/services/bluetooth_config/public/mojom/cros_bluetooth_config.mojom.h" | ||
#include "device/bluetooth/bluetooth_adapter.h" | ||
|
||
namespace chromeos { | ||
namespace bluetooth_config { | ||
|
||
// Concrete DeviceCache implementation. When this class is created, it uses | ||
// BluetoothAdapter to fetch an initial list of devices; then, it observes | ||
// BluetoothAdapter so that it can update the cache when devices are added, | ||
// removed, or changed. | ||
// | ||
// Additionally, it uses AdapterStateController to ensure that no devices are | ||
// returned unless Bluetooth is enabled or enabling. | ||
class DeviceCacheImpl : public DeviceCache, | ||
public AdapterStateController::Observer, | ||
public device::BluetoothAdapter::Observer { | ||
public: | ||
DeviceCacheImpl(AdapterStateController* adapter_state_controller, | ||
scoped_refptr<device::BluetoothAdapter> bluetooth_adapter); | ||
~DeviceCacheImpl() override; | ||
|
||
private: | ||
friend class DeviceCacheImplTest; | ||
|
||
// DeviceCache: | ||
std::vector<mojom::PairedBluetoothDevicePropertiesPtr> | ||
PerformGetPairedDevices() const override; | ||
|
||
// AdapterStateController::Observer: | ||
void OnAdapterStateChanged() override; | ||
|
||
// device::BluetoothAdapter::Observer: | ||
void DeviceAdded(device::BluetoothAdapter* adapter, | ||
device::BluetoothDevice* device) override; | ||
void DeviceRemoved(device::BluetoothAdapter* adapter, | ||
device::BluetoothDevice* device) override; | ||
void DeviceChanged(device::BluetoothAdapter* adapter, | ||
device::BluetoothDevice* device) override; | ||
void DevicePairedChanged(device::BluetoothAdapter* adapter, | ||
device::BluetoothDevice* device, | ||
bool new_paired_status) override; | ||
void DeviceConnectedStateChanged(device::BluetoothAdapter* adapter, | ||
device::BluetoothDevice* device, | ||
bool is_now_connected) override; | ||
void DeviceBatteryChanged( | ||
device::BluetoothAdapter* adapter, | ||
device::BluetoothDevice* device, | ||
absl::optional<uint8_t> new_battery_percentage) override; | ||
|
||
// Fetches all known devices from BluetoothAdapter. | ||
void FetchInitialPairedDeviceList(); | ||
|
||
// Sorts |paired_devices_| based on connection state. This function is called | ||
// each time a device is added to the list. This is not particularly | ||
// efficient, but the list is expected to be small and is only sorted when its | ||
// contents change. | ||
void SortPairedDeviceList(); | ||
|
||
// Adds |device| to |paired_devices_|, but only if |device| is paired. If the | ||
// device was already present in the list, this function updates its metadata | ||
// to reflect up-to-date values. This function sorts the list after a new | ||
// element is inserted. | ||
void AttemptSetDeviceInPairedDeviceList(device::BluetoothDevice* device); | ||
|
||
// Removes |device| from |paired_devices_| if it exists in the list. | ||
void RemoveFromPairedDeviceList(device::BluetoothDevice* device); | ||
|
||
// Attempts to add updated metadata about |device| to |paired_devices_|. | ||
void AttemptUpdatePairedDeviceMetadata(device::BluetoothDevice* device); | ||
|
||
scoped_refptr<device::BluetoothAdapter> bluetooth_adapter_; | ||
|
||
// Sorted by connection status. | ||
std::vector<mojom::PairedBluetoothDevicePropertiesPtr> paired_devices_; | ||
|
||
base::ScopedObservation<AdapterStateController, | ||
AdapterStateController::Observer> | ||
adapter_state_controller_observation_{this}; | ||
base::ScopedObservation<device::BluetoothAdapter, | ||
device::BluetoothAdapter::Observer> | ||
adapter_observation_{this}; | ||
}; | ||
|
||
} // namespace bluetooth_config | ||
} // namespace chromeos | ||
|
||
#endif // CHROMEOS_SERVICES_BLUETOOTH_CONFIG_DEVICE_CACHE_IMPL_H_ |
Oops, something went wrong.