123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196 |
- // 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 "ash/system/bluetooth/bluetooth_device_list_controller_impl.h"
- #include "ash/constants/ash_features.h"
- #include "ash/strings/grit/ash_strings.h"
- #include "ash/system/bluetooth/bluetooth_detailed_view.h"
- #include "ash/system/bluetooth/bluetooth_device_list_item_view.h"
- #include "ash/system/tray/tray_popup_utils.h"
- #include "ash/system/tray/tri_view.h"
- #include "base/check.h"
- #include "ui/gfx/paint_vector_icon.h"
- #include "ui/views/controls/separator.h"
- #include "ui/views/view.h"
- namespace ash {
- namespace {
- using chromeos::bluetooth_config::mojom::PairedBluetoothDevicePropertiesPtr;
- // Helper function to remove |*view| from its view hierarchy, delete the view,
- // and reset the value of |*view| to be |nullptr|.
- template <class T>
- void RemoveAndResetViewIfExists(T** view) {
- DCHECK(view);
- if (!*view)
- return;
- views::View* parent = (*view)->parent();
- if (parent) {
- parent->RemoveChildViewT(*view);
- *view = nullptr;
- }
- }
- } // namespace
- BluetoothDeviceListControllerImpl::BluetoothDeviceListControllerImpl(
- BluetoothDetailedView* bluetooth_detailed_view)
- : bluetooth_detailed_view_(bluetooth_detailed_view) {
- DCHECK(ash::features::IsBluetoothRevampEnabled());
- }
- BluetoothDeviceListControllerImpl::~BluetoothDeviceListControllerImpl() =
- default;
- void BluetoothDeviceListControllerImpl::UpdateBluetoothEnabledState(
- bool enabled) {
- if (is_bluetooth_enabled_ && !enabled) {
- device_id_to_view_map_.clear();
- device_list_separator_ = nullptr;
- connected_sub_header_ = nullptr;
- no_device_connected_sub_header_ = nullptr;
- previously_connected_sub_header_ = nullptr;
- bluetooth_detailed_view_->device_list()->RemoveAllChildViews();
- }
- is_bluetooth_enabled_ = enabled;
- }
- void BluetoothDeviceListControllerImpl::UpdateDeviceList(
- const PairedBluetoothDevicePropertiesPtrs& connected,
- const PairedBluetoothDevicePropertiesPtrs& previously_connected) {
- DCHECK(is_bluetooth_enabled_);
- // This function will create views for new devices, re-use views for existing
- // devices, and remove views for devices that no longer exist. To do this, we
- // keep track of all the preexisting views in |previous_views|, removing a
- // view from this map when the corresponding device is found in |connected| or
- // |previously_connected|. Before returning, any view remaining in
- // |previous_views| is no longer needed and is deleted.
- base::flat_map<std::string, BluetoothDeviceListItemView*> previous_views =
- std::move(device_id_to_view_map_);
- device_id_to_view_map_.clear();
- // Since we re-use views when possible, we need to re-order them to match the
- // order of the devices we are provided with. We use |index| to keep track of
- // the next index within the device list where a view should be placed, i.e.
- // all views before |index| are in their final position.
- size_t index = 0;
- // The list of connected devices.
- if (!connected.empty()) {
- connected_sub_header_ = CreateSubHeaderIfMissingAndReorder(
- connected_sub_header_,
- IDS_ASH_STATUS_TRAY_BLUETOOTH_CURRENTLY_CONNECTED_DEVICES, index);
- // Increment |index| since this position was taken by
- // |connected_sub_header_|.
- index++;
- index = CreateViewsIfMissingAndReorder(connected, &previous_views, index);
- } else {
- RemoveAndResetViewIfExists(&connected_sub_header_);
- }
- // The separator between the connected and previously connected devices.
- if (!connected.empty() && !previously_connected.empty()) {
- if (!device_list_separator_) {
- device_list_separator_ =
- bluetooth_detailed_view_->device_list()->AddChildView(
- TrayPopupUtils::CreateListSubHeaderSeparator());
- }
- bluetooth_detailed_view_->device_list()->ReorderChildView(
- device_list_separator_, index);
- // Increment |index| since this position was taken by
- // |device_list_separator_|.
- index++;
- } else {
- RemoveAndResetViewIfExists(&device_list_separator_);
- }
- // The previously connected devices.
- if (!previously_connected.empty()) {
- previously_connected_sub_header_ = CreateSubHeaderIfMissingAndReorder(
- previously_connected_sub_header_,
- IDS_ASH_STATUS_TRAY_BLUETOOTH_PREVIOUSLY_CONNECTED_DEVICES, index);
- // Increment |index| since this position was taken by
- // |previously_connected_sub_header_|.
- index++;
- // Ignore the returned index since we are now done re-ordering the list.
- CreateViewsIfMissingAndReorder(previously_connected, &previous_views,
- index);
- } else {
- RemoveAndResetViewIfExists(&previously_connected_sub_header_);
- }
- // The header when there are no connected or previously connected devices.
- if (device_id_to_view_map_.empty()) {
- no_device_connected_sub_header_ = CreateSubHeaderIfMissingAndReorder(
- no_device_connected_sub_header_,
- IDS_ASH_STATUS_TRAY_BLUETOOTH_NO_DEVICE_CONNECTED, index);
- } else {
- RemoveAndResetViewIfExists(&no_device_connected_sub_header_);
- }
- for (const auto& id_and_view : previous_views) {
- bluetooth_detailed_view_->device_list()->RemoveChildViewT(
- id_and_view.second);
- }
- bluetooth_detailed_view_->NotifyDeviceListChanged();
- }
- TriView* BluetoothDeviceListControllerImpl::CreateSubHeaderIfMissingAndReorder(
- TriView* sub_header,
- int text_id,
- size_t index) {
- if (!sub_header) {
- sub_header = bluetooth_detailed_view_->AddDeviceListSubHeader(
- gfx::kNoneIcon, text_id);
- }
- bluetooth_detailed_view_->device_list()->ReorderChildView(sub_header, index);
- return sub_header;
- }
- size_t BluetoothDeviceListControllerImpl::CreateViewsIfMissingAndReorder(
- const PairedBluetoothDevicePropertiesPtrs& device_property_list,
- base::flat_map<std::string, BluetoothDeviceListItemView*>* previous_views,
- size_t index) {
- DCHECK(previous_views);
- BluetoothDeviceListItemView* device_view = nullptr;
- const size_t device_count = device_property_list.size();
- for (size_t i = 0; i < device_count; ++i) {
- const PairedBluetoothDevicePropertiesPtr& device_properties =
- device_property_list.at(i);
- const std::string& device_id = device_properties->device_properties->id;
- auto it = previous_views->find(device_id);
- if (it == previous_views->end()) {
- device_view = bluetooth_detailed_view_->AddDeviceListItem();
- } else {
- device_view = it->second;
- previous_views->erase(it);
- }
- device_id_to_view_map_.emplace(device_id, device_view);
- device_view->UpdateDeviceProperties(i, device_count, device_properties);
- bluetooth_detailed_view_->device_list()->ReorderChildView(device_view,
- index);
- // Increment |index| since this position was taken by |device_view|.
- index++;
- }
- return index;
- }
- } // namespace ash
|