Adds Bluetooth Unavailable State View to Bluetooth Detailed Tray View
This CL creates an unavailable state view for when the Bluetooth is unavailable that is hidden behind a feature flag. Bug: 357945367 Change-Id: I50df40ec4c5e121971f89b875963c075969866b7 Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/5779783 Auto-Submit: Bhuvana Betini <bbetini@google.com> Reviewed-by: Ahmed Mehfooz <amehfooz@chromium.org> Reviewed-by: Andre Le <leandre@chromium.org> Commit-Queue: Bhuvana Betini <bbetini@google.com> Reviewed-by: Xiyuan Xia <xiyuan@chromium.org> Cr-Commit-Position: refs/heads/main@{#1343127}
This commit is contained in:

committed by
Chromium LUCI CQ

parent
b9b5f34280
commit
fd36ac82ee
ash
ash_strings.grd
ash_strings_grd
IDS_ASH_STATUS_TRAY_BLUETOOTH_UNAVAILABLE_STATE_SUBTITLE.png.sha1IDS_ASH_STATUS_TRAY_BLUETOOTH_UNAVAILABLE_STATE_TITLE.png.sha1
public
cpp
resources
system
@ -666,6 +666,12 @@ Style notes:
|
||||
<message name="IDS_ASH_STATUS_TRAY_BLUETOOTH_UNAVAILABLE_TOOLTIP" desc="The tooltip text to notify that bluetooth is unavailable.">
|
||||
Bluetooth is unavailable
|
||||
</message>
|
||||
<message name="IDS_ASH_STATUS_TRAY_BLUETOOTH_UNAVAILABLE_STATE_TITLE" desc="The main label for the Bluetooth Quick Settings detailed view when Bluetooth is unavailable.">
|
||||
Bluetooth unavailable
|
||||
</message>
|
||||
<message name="IDS_ASH_STATUS_TRAY_BLUETOOTH_UNAVAILABLE_STATE_SUBTITLE" desc="The secondary label for the Bluetooth Quick Settings detailed view when Bluetooth is unavailable.">
|
||||
Try shutting down your device.
|
||||
</message>
|
||||
<message name="IDS_ASH_STATUS_TRAY_BLUETOOTH_MULTIPLE_DEVICES_CONNECTED_TOOLTIP_LEGACY" desc="The tooltip text to notify that multiple bluetooth devices are connected. [ICU Syntax]">
|
||||
{NUM_DEVICES, plural,
|
||||
=1 {Connected to a device}
|
||||
|
@ -0,0 +1 @@
|
||||
a81f43cb0e80e44ab788ce45bfa250cd4ca63524
|
@ -0,0 +1 @@
|
||||
ff5af3b6e966fdbf562f366720876bc0858fe4fd
|
@ -70,6 +70,8 @@
|
||||
<structure type="lottie" name="IDR_KEYBOARD_FN_KEY_NUDGE_IMAGE" file="unscaled_resources/keyboard_fn_key_nudge_image.json" compress="gzip" />
|
||||
<!-- Capslock Nudge -->
|
||||
<structure type="lottie" name="IDR_KEYBOARD_CAPSLOCK_KEY_NUDGE_IMAGE" file="unscaled_resources/keyboard_capslock_key_nudge_image.json" compress="gzip" />
|
||||
<!-- System Tray Bluetooth Unavailable Images -->
|
||||
<structure type="lottie" name="IDR_TRAY_BLUETOOTH_UNAVAILABLE_STATE_IMAGE" file="unscaled_resources/bluetooth_unavailable_state_image.json" compress="gzip" />
|
||||
</structures>
|
||||
</release>
|
||||
</grit>
|
||||
|
File diff suppressed because one or more lines are too long
@ -21,6 +21,7 @@
|
||||
#include "build/chromeos_buildflags.h"
|
||||
#include "chromeos/ash/components/network/network_event_log.h"
|
||||
#include "chromeos/ash/services/bluetooth_config/public/cpp/cros_bluetooth_config_util.h"
|
||||
#include "chromeos/constants/chromeos_features.h"
|
||||
#include "mojo/public/cpp/bindings/clone_traits.h"
|
||||
#include "ui/base/l10n/l10n_util.h"
|
||||
#include "ui/views/view.h"
|
||||
@ -84,7 +85,12 @@ std::u16string BluetoothDetailedViewController::GetAccessibleName() const {
|
||||
|
||||
void BluetoothDetailedViewController::OnPropertiesUpdated(
|
||||
bluetooth_config::mojom::BluetoothSystemPropertiesPtr properties) {
|
||||
if (properties->system_state == BluetoothSystemState::kUnavailable) {
|
||||
// The tray controller should only be transitioning to the main view when this
|
||||
// feature is disabled since the detailed tray view and the Bluetooth Pod in
|
||||
// QS would be hidden. However, when the feature is enabled, the Bluetooth Pod
|
||||
// is visible and the user should be able to see the detailed tray view.
|
||||
if (!chromeos::features::IsBluetoothWifiQSPodRefreshEnabled() &&
|
||||
properties->system_state == BluetoothSystemState::kUnavailable) {
|
||||
tray_controller_->TransitionToMainView(
|
||||
/*restore_focus=*/true); // Deletes |this|.
|
||||
return;
|
||||
|
@ -9,6 +9,7 @@
|
||||
|
||||
#include "ash/ash_element_identifiers.h"
|
||||
#include "ash/bubble/bubble_utils.h"
|
||||
#include "ash/public/cpp/resources/grit/ash_public_unscaled_resources.h"
|
||||
#include "ash/public/cpp/system_tray_client.h"
|
||||
#include "ash/resources/vector_icons/vector_icons.h"
|
||||
#include "ash/shell.h"
|
||||
@ -68,6 +69,13 @@ BluetoothDetailedViewImpl::BluetoothDetailedViewImpl(
|
||||
CreateScrollableList();
|
||||
CreateTopContainer();
|
||||
CreateMainContainer();
|
||||
if (chromeos::features::IsBluetoothWifiQSPodRefreshEnabled()) {
|
||||
CreateZeroStateView(std::make_unique<ZeroStateView>(
|
||||
/*image_id=*/IDR_TRAY_BLUETOOTH_UNAVAILABLE_STATE_IMAGE,
|
||||
/*title_id=*/IDS_ASH_STATUS_TRAY_BLUETOOTH_UNAVAILABLE_STATE_TITLE,
|
||||
/*subtitle_id=*/
|
||||
IDS_ASH_STATUS_TRAY_BLUETOOTH_UNAVAILABLE_STATE_SUBTITLE));
|
||||
}
|
||||
UpdateBluetoothEnabledState(BluetoothSystemState::kDisabled);
|
||||
device::RecordUiSurfaceDisplayed(
|
||||
device::BluetoothUiSurface::kBluetoothQuickSettings);
|
||||
@ -81,6 +89,15 @@ views::View* BluetoothDetailedViewImpl::GetAsView() {
|
||||
|
||||
void BluetoothDetailedViewImpl::UpdateBluetoothEnabledState(
|
||||
const BluetoothSystemState system_state) {
|
||||
if (chromeos::features::IsBluetoothWifiQSPodRefreshEnabled() &&
|
||||
system_state == BluetoothSystemState::kUnavailable) {
|
||||
SetZeroStateViewVisibility(true);
|
||||
return;
|
||||
}
|
||||
if (chromeos::features::IsBluetoothWifiQSPodRefreshEnabled()) {
|
||||
SetZeroStateViewVisibility(false);
|
||||
}
|
||||
|
||||
bool is_enabled_or_enabling = IsBluetoothEnabledOrEnabling(system_state);
|
||||
|
||||
// Use square corners on the bottom edge when Bluetooth is enabled.
|
||||
|
@ -4,6 +4,8 @@
|
||||
|
||||
#include <string>
|
||||
|
||||
#include "ash/system/bluetooth/bluetooth_detailed_view_impl.h"
|
||||
#include "ash/system/tray/fake_detailed_view_delegate.h"
|
||||
#include "ash/system/tray/tray_detailed_view.h"
|
||||
#include "ash/system/unified/quick_settings_view.h"
|
||||
#include "ash/system/unified/unified_system_tray.h"
|
||||
@ -13,15 +15,20 @@
|
||||
#include "ash/test/ash_test_helper.h"
|
||||
#include "ash/test/pixel/ash_pixel_differ.h"
|
||||
#include "ash/test/pixel/ash_pixel_test_init_params.h"
|
||||
#include "base/test/scoped_feature_list.h"
|
||||
#include "chromeos/ash/services/bluetooth_config/fake_adapter_state_controller.h"
|
||||
#include "chromeos/ash/services/bluetooth_config/fake_device_cache.h"
|
||||
#include "chromeos/ash/services/bluetooth_config/public/mojom/cros_bluetooth_config.mojom-shared.h"
|
||||
#include "chromeos/ash/services/bluetooth_config/public/mojom/cros_bluetooth_config.mojom.h"
|
||||
#include "chromeos/ash/services/bluetooth_config/scoped_bluetooth_config_test_helper.h"
|
||||
#include "chromeos/constants/chromeos_features.h"
|
||||
|
||||
namespace ash {
|
||||
namespace {
|
||||
|
||||
using bluetooth_config::ScopedBluetoothConfigTestHelper;
|
||||
using bluetooth_config::mojom::BluetoothDeviceProperties;
|
||||
using bluetooth_config::mojom::BluetoothSystemState;
|
||||
using bluetooth_config::mojom::DeviceConnectionState;
|
||||
using bluetooth_config::mojom::PairedBluetoothDeviceProperties;
|
||||
using bluetooth_config::mojom::PairedBluetoothDevicePropertiesPtr;
|
||||
@ -38,10 +45,26 @@ PairedBluetoothDevicePropertiesPtr CreatePairedDevice(
|
||||
return paired_properties;
|
||||
}
|
||||
|
||||
// Returns appropriate screenshot suffix based on whether the feature flag is
|
||||
// enabled.
|
||||
std::string GetScreenshotName(const std::string& test_name, bool enabled) {
|
||||
return test_name + (enabled ? "_unavailable_state_enabled"
|
||||
: "_unavailable_state_disabled");
|
||||
}
|
||||
|
||||
// Pixel tests for the quick settings Bluetooth detailed view.
|
||||
class BluetoothDetailedViewImplPixelTest : public AshTestBase {
|
||||
class BluetoothDetailedViewImplPixelTest
|
||||
: public AshTestBase,
|
||||
public testing::WithParamInterface<bool> {
|
||||
public:
|
||||
BluetoothDetailedViewImplPixelTest() = default;
|
||||
BluetoothDetailedViewImplPixelTest() {
|
||||
scoped_feature_list_ = std::make_unique<base::test::ScopedFeatureList>();
|
||||
scoped_feature_list_->InitWithFeatureState(
|
||||
chromeos::features::kBluetoothWifiQSPodRefresh,
|
||||
IsBluetoothWifiQSPodRefreshEnabled());
|
||||
}
|
||||
|
||||
bool IsBluetoothWifiQSPodRefreshEnabled() { return GetParam(); }
|
||||
|
||||
// AshTestBase:
|
||||
std::optional<pixel_test::InitParams> CreatePixelTestInitParams()
|
||||
@ -57,9 +80,25 @@ class BluetoothDetailedViewImplPixelTest : public AshTestBase {
|
||||
->fake_device_cache()
|
||||
->SetPairedDevices(std::move(paired_devices));
|
||||
}
|
||||
|
||||
void SetBluetoothSystemState(BluetoothSystemState system_state) {
|
||||
ash_test_helper()
|
||||
->bluetooth_config_test_helper()
|
||||
->fake_adapter_state_controller()
|
||||
->SetSystemState(system_state);
|
||||
base::RunLoop().RunUntilIdle();
|
||||
}
|
||||
|
||||
private:
|
||||
std::unique_ptr<base::test::ScopedFeatureList> scoped_feature_list_;
|
||||
};
|
||||
|
||||
TEST_F(BluetoothDetailedViewImplPixelTest, Basics) {
|
||||
INSTANTIATE_TEST_SUITE_P(
|
||||
All,
|
||||
BluetoothDetailedViewImplPixelTest,
|
||||
/*IsBluetoothWifiQSPodRefreshEnabled()=*/testing::Bool());
|
||||
|
||||
TEST_P(BluetoothDetailedViewImplPixelTest, Basics) {
|
||||
// Create test devices.
|
||||
std::vector<PairedBluetoothDevicePropertiesPtr> paired_devices;
|
||||
paired_devices.push_back(
|
||||
@ -85,9 +124,38 @@ TEST_F(BluetoothDetailedViewImplPixelTest, Basics) {
|
||||
|
||||
// Compare pixels.
|
||||
EXPECT_TRUE(GetPixelDiffer()->CompareUiComponentsOnPrimaryScreen(
|
||||
"check_view",
|
||||
GetScreenshotName("check_view", IsBluetoothWifiQSPodRefreshEnabled()),
|
||||
/*revision_number=*/9, detailed_view));
|
||||
}
|
||||
|
||||
TEST_P(BluetoothDetailedViewImplPixelTest, BluetoothUnavailable) {
|
||||
if (!IsBluetoothWifiQSPodRefreshEnabled()) {
|
||||
GTEST_SKIP() << "If Bluetooth is unavailable the BluetoothDetailedView is "
|
||||
"not accessible";
|
||||
}
|
||||
SetBluetoothSystemState(BluetoothSystemState::kUnavailable);
|
||||
|
||||
// Show the system tray bubble.
|
||||
UnifiedSystemTray* system_tray = GetPrimaryUnifiedSystemTray();
|
||||
system_tray->ShowBubble();
|
||||
ASSERT_TRUE(system_tray->bubble());
|
||||
|
||||
// Show the Bluetooth detailed view.
|
||||
system_tray->bubble()
|
||||
->unified_system_tray_controller()
|
||||
->ShowBluetoothDetailedView();
|
||||
TrayDetailedView* detailed_view =
|
||||
system_tray->bubble()
|
||||
->quick_settings_view()
|
||||
->GetDetailedViewForTest<TrayDetailedView>();
|
||||
ASSERT_TRUE(detailed_view);
|
||||
|
||||
// Compare pixels.
|
||||
EXPECT_TRUE(GetPixelDiffer()->CompareUiComponentsOnPrimaryScreen(
|
||||
GetScreenshotName("bluetooth_unavailable_view",
|
||||
IsBluetoothWifiQSPodRefreshEnabled()),
|
||||
/*revision_number=*/0, detailed_view));
|
||||
}
|
||||
|
||||
} // namespace
|
||||
} // namespace ash
|
||||
|
@ -14,8 +14,11 @@
|
||||
#include "ash/system/tray/hover_highlight_view.h"
|
||||
#include "ash/test/ash_test_base.h"
|
||||
#include "base/memory/raw_ptr.h"
|
||||
#include "base/test/scoped_feature_list.h"
|
||||
#include "chromeos/constants/chromeos_features.h"
|
||||
#include "mojo/public/cpp/bindings/clone_traits.h"
|
||||
#include "ui/views/controls/label.h"
|
||||
#include "ui/views/controls/scroll_view.h"
|
||||
#include "ui/views/test/views_test_utils.h"
|
||||
#include "ui/views/widget/widget.h"
|
||||
|
||||
@ -57,8 +60,16 @@ class FakeBluetoothDetailedViewDelegate
|
||||
|
||||
} // namespace
|
||||
|
||||
class BluetoothDetailedViewImplTest : public AshTestBase {
|
||||
class BluetoothDetailedViewImplTest : public AshTestBase,
|
||||
public testing::WithParamInterface<bool> {
|
||||
public:
|
||||
BluetoothDetailedViewImplTest() {
|
||||
scoped_feature_list_ = std::make_unique<base::test::ScopedFeatureList>();
|
||||
scoped_feature_list_->InitWithFeatureState(
|
||||
chromeos::features::kBluetoothWifiQSPodRefresh,
|
||||
IsBluetoothWifiQSPodRefreshEnabled());
|
||||
}
|
||||
|
||||
void SetUp() override {
|
||||
AshTestBase::SetUp();
|
||||
|
||||
@ -81,6 +92,8 @@ class BluetoothDetailedViewImplTest : public AshTestBase {
|
||||
return bluetooth_detailed_view_->settings_button_;
|
||||
}
|
||||
|
||||
bool IsBluetoothWifiQSPodRefreshEnabled() { return GetParam(); }
|
||||
|
||||
HoverHighlightView* GetToggleRow() {
|
||||
return bluetooth_detailed_view_->toggle_row_;
|
||||
}
|
||||
@ -100,9 +113,15 @@ class BluetoothDetailedViewImplTest : public AshTestBase {
|
||||
FakeDetailedViewDelegate detailed_view_delegate_;
|
||||
raw_ptr<BluetoothDetailedViewImpl, DanglingUntriaged>
|
||||
bluetooth_detailed_view_ = nullptr;
|
||||
std::unique_ptr<base::test::ScopedFeatureList> scoped_feature_list_;
|
||||
};
|
||||
|
||||
TEST_F(BluetoothDetailedViewImplTest, PressingSettingsButtonOpensSettings) {
|
||||
INSTANTIATE_TEST_SUITE_P(
|
||||
All,
|
||||
BluetoothDetailedViewImplTest,
|
||||
/*IsBluetoothWifiQSPodRefreshEnabled()=*/testing::Bool());
|
||||
|
||||
TEST_P(BluetoothDetailedViewImplTest, PressingSettingsButtonOpensSettings) {
|
||||
views::Button* settings_button = GetSettingsButton();
|
||||
|
||||
// Clicking the button at the lock screen does nothing.
|
||||
@ -120,7 +139,7 @@ TEST_F(BluetoothDetailedViewImplTest, PressingSettingsButtonOpensSettings) {
|
||||
EXPECT_EQ(1u, detailed_view_delegate_.close_bubble_call_count());
|
||||
}
|
||||
|
||||
TEST_F(BluetoothDetailedViewImplTest,
|
||||
TEST_P(BluetoothDetailedViewImplTest,
|
||||
UpdateBluetoothEnabledStateChangesUIState) {
|
||||
HoverHighlightView* toggle_row = GetToggleRow();
|
||||
Switch* toggle_button = GetToggleButton();
|
||||
@ -138,6 +157,12 @@ TEST_F(BluetoothDetailedViewImplTest,
|
||||
toggle_button->GetTooltipText());
|
||||
EXPECT_TRUE(main_container->GetVisible());
|
||||
EXPECT_TRUE(pair_new_device_view->GetVisible());
|
||||
if (IsBluetoothWifiQSPodRefreshEnabled()) {
|
||||
EXPECT_FALSE(
|
||||
bluetooth_detailed_view_->zero_state_view_for_testing()->GetVisible());
|
||||
}
|
||||
EXPECT_TRUE(
|
||||
bluetooth_detailed_view_->scroll_view_for_testing()->GetVisible());
|
||||
|
||||
bluetooth_detailed_view_->UpdateBluetoothEnabledState(
|
||||
BluetoothSystemState::kDisabled);
|
||||
@ -149,7 +174,12 @@ TEST_F(BluetoothDetailedViewImplTest,
|
||||
EXPECT_EQ(u"Toggle Bluetooth. Bluetooth is off.",
|
||||
toggle_button->GetTooltipText());
|
||||
EXPECT_FALSE(main_container->GetVisible());
|
||||
|
||||
if (IsBluetoothWifiQSPodRefreshEnabled()) {
|
||||
EXPECT_FALSE(
|
||||
bluetooth_detailed_view_->zero_state_view_for_testing()->GetVisible());
|
||||
}
|
||||
EXPECT_TRUE(
|
||||
bluetooth_detailed_view_->scroll_view_for_testing()->GetVisible());
|
||||
bluetooth_detailed_view_->UpdateBluetoothEnabledState(
|
||||
BluetoothSystemState::kEnabling);
|
||||
EXPECT_EQ(u"On", toggle_row->text_label()->GetText());
|
||||
@ -160,9 +190,24 @@ TEST_F(BluetoothDetailedViewImplTest,
|
||||
toggle_button->GetTooltipText());
|
||||
EXPECT_TRUE(main_container->GetVisible());
|
||||
EXPECT_FALSE(pair_new_device_view->GetVisible());
|
||||
if (IsBluetoothWifiQSPodRefreshEnabled()) {
|
||||
EXPECT_FALSE(
|
||||
bluetooth_detailed_view_->zero_state_view_for_testing()->GetVisible());
|
||||
}
|
||||
EXPECT_TRUE(
|
||||
bluetooth_detailed_view_->scroll_view_for_testing()->GetVisible());
|
||||
|
||||
bluetooth_detailed_view_->UpdateBluetoothEnabledState(
|
||||
BluetoothSystemState::kUnavailable);
|
||||
if (IsBluetoothWifiQSPodRefreshEnabled()) {
|
||||
EXPECT_TRUE(
|
||||
bluetooth_detailed_view_->zero_state_view_for_testing()->GetVisible());
|
||||
EXPECT_FALSE(
|
||||
bluetooth_detailed_view_->scroll_view_for_testing()->GetVisible());
|
||||
}
|
||||
}
|
||||
|
||||
TEST_F(BluetoothDetailedViewImplTest, PressingToggleRowNotifiesDelegate) {
|
||||
TEST_P(BluetoothDetailedViewImplTest, PressingToggleRowNotifiesDelegate) {
|
||||
HoverHighlightView* toggle_row = GetToggleRow();
|
||||
EXPECT_FALSE(bluetooth_detailed_view_delegate_.last_toggle_state_);
|
||||
|
||||
@ -171,7 +216,7 @@ TEST_F(BluetoothDetailedViewImplTest, PressingToggleRowNotifiesDelegate) {
|
||||
EXPECT_TRUE(bluetooth_detailed_view_delegate_.last_toggle_state_);
|
||||
}
|
||||
|
||||
TEST_F(BluetoothDetailedViewImplTest, PressingToggleButtonNotifiesDelegate) {
|
||||
TEST_P(BluetoothDetailedViewImplTest, PressingToggleButtonNotifiesDelegate) {
|
||||
Switch* toggle_button = GetToggleButton();
|
||||
views::Button* pair_new_device_view = GetPairNewDeviceView();
|
||||
|
||||
@ -186,7 +231,7 @@ TEST_F(BluetoothDetailedViewImplTest, PressingToggleButtonNotifiesDelegate) {
|
||||
EXPECT_FALSE(pair_new_device_view->GetVisible());
|
||||
}
|
||||
|
||||
TEST_F(BluetoothDetailedViewImplTest, PressingPairNewDeviceNotifiesDelegate) {
|
||||
TEST_P(BluetoothDetailedViewImplTest, PressingPairNewDeviceNotifiesDelegate) {
|
||||
bluetooth_detailed_view_->UpdateBluetoothEnabledState(
|
||||
BluetoothSystemState::kEnabled);
|
||||
views::test::RunScheduledLayout(bluetooth_detailed_view_);
|
||||
@ -198,7 +243,7 @@ TEST_F(BluetoothDetailedViewImplTest, PressingPairNewDeviceNotifiesDelegate) {
|
||||
bluetooth_detailed_view_delegate_.pair_new_device_requested_count_);
|
||||
}
|
||||
|
||||
TEST_F(BluetoothDetailedViewImplTest, SelectingDeviceListItemNotifiesDelegate) {
|
||||
TEST_P(BluetoothDetailedViewImplTest, SelectingDeviceListItemNotifiesDelegate) {
|
||||
bluetooth_detailed_view_->UpdateBluetoothEnabledState(
|
||||
BluetoothSystemState::kEnabled);
|
||||
|
||||
|
Reference in New Issue
Block a user