Reland "Added the display subpage for QsRevamp"
This is a reland of commit 5ccff3bed9
The root cause of the revert issue:
In this CL(
https://chromium-review.googlesource.com/c/chromium/src/+/4195759), we
identified the issue with the brightness slider that it cannot be
changed via keyboard, and this issue caused the tast test failure.
The fix:
We fixed the issue by reverting the logic for brightness slider(combined
the change in the above linked CL with the original CL for the display
subpage).
Original change's description:
> Added the display subpage for QsRevamp
>
> 1. Added the display detailed view for QsRevamp. This view contains a
> night light feature tile, a dark mode feature tile, and a display
> brightness slider. The title of this view is `Display` and there is a
> settings button leading to the display system settings page at the
> end of the title row.
> 2. Added corresponding unit test for display detailed view and
> parameterize unit tests for night light and dark mode feature pod
> controllers.
> 3. Applied the callback for the night light button in the main page.
> 4. Added the vector icon resource for the night light when disabled.
> Added the string for the display detailed view title.
> 5. Fixed an existing issue with the brightness slider by adding a
> variable in unified_system_tray_model to store the actual brightness
> value to render the slider.
>
> Display detailed view overview(locked screen & logged-in screen):
> https://screenshot.googleplex.com/4BDGFDMAv3By5UW
>
> Night Light feature tile different sub labels:
> https://screenshot.googleplex.com/5Uw9bbGimcvd9bG
>
> Dark Mode feature tile different sub labels:
> https://screenshot.googleplex.com/4KTbcabeF2n2x53
>
> Focus behavior:
> https://screenshot.googleplex.com/5dJtJUsPyrHbdQz
>
> Bug: b/252870817
> Change-Id: I7b89b2d21096c94b4d96280c01111a3129dd3b51
> Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/4174144
> Reviewed-by: Jiaming Cheng <jiamingc@chromium.org>
> Reviewed-by: Mitsuru Oshima <oshima@chromium.org>
> Commit-Queue: Sylvie Liu <sylvieliu@chromium.org>
> Cr-Commit-Position: refs/heads/main@{#1097004}
Bug: b/252870817
Change-Id: I4c4d86eed53df82e3e6ce57a41c6f668394e9b01
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/4198495
Reviewed-by: Alex Newcomer <newcomer@chromium.org>
Reviewed-by: Mitsuru Oshima <oshima@chromium.org>
Commit-Queue: Sylvie Liu <sylvieliu@chromium.org>
Reviewed-by: Jiaming Cheng <jiamingc@chromium.org>
Cr-Commit-Position: refs/heads/main@{#1097621}
This commit is contained in:

committed by
Chromium LUCI CQ

parent
4f2ddafd32
commit
1fbe4538d6
ash
BUILD.gnash_strings.grd
ash_strings_grd
public
resources
vector_icons
system
brightness
display_detailed_view.ccdisplay_detailed_view.hdisplay_detailed_view_unittest.ccquick_settings_display_detailed_view_controller.ccquick_settings_display_detailed_view_controller.hunified_brightness_slider_controller.ccunified_brightness_slider_controller.hunified_brightness_view.ccunified_brightness_view.hunified_brightness_view_unittest.cc
dark_mode
dark_mode_feature_pod_controller.ccdark_mode_feature_pod_controller.hdark_mode_feature_pod_controller_unittest.cc
night_light
night_light_feature_pod_controller.ccnight_light_feature_pod_controller.hnight_light_feature_pod_controller_unittest.cc
unified
@ -1190,6 +1190,10 @@ component("ash") {
|
||||
"system/bluetooth/bluetooth_notification_controller.h",
|
||||
"system/brightness/brightness_controller_chromeos.cc",
|
||||
"system/brightness/brightness_controller_chromeos.h",
|
||||
"system/brightness/display_detailed_view.cc",
|
||||
"system/brightness/display_detailed_view.h",
|
||||
"system/brightness/quick_settings_display_detailed_view_controller.cc",
|
||||
"system/brightness/quick_settings_display_detailed_view_controller.h",
|
||||
"system/brightness/unified_brightness_slider_controller.cc",
|
||||
"system/brightness/unified_brightness_slider_controller.h",
|
||||
"system/brightness/unified_brightness_view.cc",
|
||||
@ -3027,6 +3031,7 @@ test("ash_unittests") {
|
||||
"system/bluetooth/fake_bluetooth_detailed_view.h",
|
||||
"system/bluetooth/fake_bluetooth_device_list_controller.cc",
|
||||
"system/bluetooth/fake_bluetooth_device_list_controller.h",
|
||||
"system/brightness/display_detailed_view_unittest.cc",
|
||||
"system/brightness/unified_brightness_view_unittest.cc",
|
||||
"system/camera/autozoom_feature_pod_controller_unittest.cc",
|
||||
"system/camera/autozoom_toast_controller_unittest.cc",
|
||||
|
@ -2703,6 +2703,9 @@ Connect your device to power.
|
||||
<message name="IDS_ASH_STATUS_TRAY_AUDIO_INPUT" desc="The label used in audio detailed page for audio input section of ash tray pop up.">
|
||||
Input
|
||||
</message>
|
||||
<message name="IDS_ASH_STATUS_TRAY_DISPLAY" desc="The label used for the button in the status tray to show the display detailed page.">
|
||||
Display
|
||||
</message>
|
||||
<message name="IDS_ASH_STATUS_TRAY_DISPLAY_REMOVED_EXCEEDED_MAXIMUM" desc="The label used when user connects more external displays than the maximum that the device can support.">
|
||||
This device couldn't support all of your displays, so one has been disconnected
|
||||
</message>
|
||||
|
1
ash/ash_strings_grd/IDS_ASH_STATUS_TRAY_DISPLAY.png.sha1
Normal file
1
ash/ash_strings_grd/IDS_ASH_STATUS_TRAY_DISPLAY.png.sha1
Normal file
@ -0,0 +1 @@
|
||||
4fe893b2832867a95f7c85a014a56f7712e6929b
|
@ -61,6 +61,13 @@ enum ViewID {
|
||||
// Shown in system tray detailed views:
|
||||
VIEW_ID_QS_DETAILED_VIEW_BACK_BUTTON,
|
||||
|
||||
// QS revamped display detailed view:
|
||||
VIEW_ID_QS_DISPLAY_MIN,
|
||||
VIEW_ID_QS_DISPLAY_BRIGHTNESS_SLIDER = VIEW_ID_QS_DISPLAY_MIN,
|
||||
VIEW_ID_QS_DISPLAY_SCROLL_CONTENT,
|
||||
VIEW_ID_QS_DISPLAY_TILE_CONTAINER,
|
||||
VIEW_ID_QS_DISPLAY_MAX = VIEW_ID_QS_DISPLAY_TILE_CONTAINER,
|
||||
|
||||
// Status area trays:
|
||||
VIEW_ID_SA_MIN,
|
||||
VIEW_ID_SA_DATE_TRAY = VIEW_ID_SA_MIN,
|
||||
|
@ -471,6 +471,7 @@ aggregate_vector_icons("ash_vector_icons") {
|
||||
"unified_menu_brightness_medium.icon",
|
||||
"unified_menu_cast.icon",
|
||||
"unified_menu_dark_mode.icon",
|
||||
"unified_menu_dark_mode_off.icon",
|
||||
"unified_menu_do_not_disturb.icon",
|
||||
"unified_menu_expand.icon",
|
||||
"unified_menu_info.icon",
|
||||
|
30
ash/resources/vector_icons/unified_menu_dark_mode_off.icon
Normal file
30
ash/resources/vector_icons/unified_menu_dark_mode_off.icon
Normal file
@ -0,0 +1,30 @@
|
||||
// Copyright 2023 The Chromium Authors
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
CANVAS_DIMENSIONS, 20,
|
||||
MOVE_TO, 3.64f, 5.14f,
|
||||
LINE_TO, 2, 3.5f,
|
||||
LINE_TO, 3.24f, 2.26f,
|
||||
LINE_TO, 18.09f, 17.11f,
|
||||
LINE_TO, 16.85f, 18.35f,
|
||||
LINE_TO, 14.86f, 16.36f,
|
||||
CUBIC_TO, 13.51f, 17.39f, 11.83f, 18, 10, 18,
|
||||
CUBIC_TO, 5.58f, 18, 2, 14.42f, 2, 10,
|
||||
CUBIC_TO, 2, 8.17f, 2.61f, 6.49f, 3.64f, 5.14f,
|
||||
CLOSE,
|
||||
MOVE_TO, 13.51f, 15.01f,
|
||||
CUBIC_TO, 12.52f, 15.71f, 11.31f, 16.12f, 10, 16.12f,
|
||||
V_LINE_TO, 11.5f,
|
||||
LINE_TO, 13.51f, 15.01f,
|
||||
CLOSE,
|
||||
MOVE_TO, 16.12f, 10,
|
||||
CUBIC_TO, 16.12f, 10.79f, 15.97f, 11.55f, 15.69f, 12.24f,
|
||||
LINE_TO, 17.11f, 13.66f,
|
||||
CUBIC_TO, 17.68f, 12.57f, 18, 11.32f, 18, 10,
|
||||
CUBIC_TO, 18, 5.58f, 14.42f, 2, 10, 2,
|
||||
CUBIC_TO, 8.68f, 2, 7.43f, 2.32f, 6.34f, 2.89f,
|
||||
LINE_TO, 10, 6.55f,
|
||||
V_LINE_TO, 3.88f,
|
||||
CUBIC_TO, 13.38f, 3.88f, 16.12f, 6.62f, 16.12f, 10,
|
||||
CLOSE
|
133
ash/system/brightness/display_detailed_view.cc
Normal file
133
ash/system/brightness/display_detailed_view.cc
Normal file
@ -0,0 +1,133 @@
|
||||
// Copyright 2023 The Chromium Authors
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
#include "ash/system/brightness/display_detailed_view.h"
|
||||
|
||||
#include <memory>
|
||||
|
||||
#include "ash/public/cpp/ash_view_ids.h"
|
||||
#include "ash/public/cpp/system_tray_client.h"
|
||||
#include "ash/root_window_controller.h"
|
||||
#include "ash/shell.h"
|
||||
#include "ash/strings/grit/ash_strings.h"
|
||||
#include "ash/system/brightness/unified_brightness_slider_controller.h"
|
||||
#include "ash/system/dark_mode/dark_mode_feature_pod_controller.h"
|
||||
#include "ash/system/model/system_tray_model.h"
|
||||
#include "ash/system/night_light/night_light_feature_pod_controller.h"
|
||||
#include "ash/system/status_area_widget.h"
|
||||
#include "ash/system/tray/detailed_view_delegate.h"
|
||||
#include "ash/system/tray/tray_popup_utils.h"
|
||||
#include "ash/system/unified/feature_tile.h"
|
||||
#include "ash/system/unified/unified_system_tray.h"
|
||||
#include "ash/system/unified/unified_system_tray_controller.h"
|
||||
#include "ui/base/metadata/metadata_impl_macros.h"
|
||||
#include "ui/gfx/geometry/insets.h"
|
||||
#include "ui/views/border.h"
|
||||
#include "ui/views/controls/scroll_view.h"
|
||||
#include "ui/views/layout/flex_layout.h"
|
||||
#include "ui/views/view.h"
|
||||
#include "ui/views/view_class_properties.h"
|
||||
|
||||
namespace ash {
|
||||
|
||||
namespace {
|
||||
|
||||
constexpr auto kScrollViewMargin = gfx::Insets::TLBR(0, 12, 16, 12);
|
||||
constexpr auto kTileMargin = gfx::Insets::TLBR(1, 4, 8, 4);
|
||||
constexpr auto kSliderPadding = gfx::Insets::TLBR(4, 0, 0, 0);
|
||||
constexpr auto kSliderBorder = gfx::Insets::VH(0, 4);
|
||||
|
||||
} // namespace
|
||||
|
||||
DisplayDetailedView::DisplayDetailedView(
|
||||
DetailedViewDelegate* delegate,
|
||||
UnifiedSystemTrayController* tray_controller)
|
||||
: TrayDetailedView(delegate),
|
||||
unified_system_tray_controller_(tray_controller) {
|
||||
CreateScrollableList();
|
||||
CreateTitleRow(IDS_ASH_STATUS_TRAY_DISPLAY);
|
||||
CreateTitleSettingsButton();
|
||||
// Sets the margin for `ScrollView` to leave some space for the focus ring.
|
||||
scroller()->SetProperty(views::kMarginsKey, kScrollViewMargin);
|
||||
|
||||
auto night_light_controller =
|
||||
std::make_unique<NightLightFeaturePodController>(
|
||||
unified_system_tray_controller_);
|
||||
auto dark_mode_controller = std::make_unique<DarkModeFeaturePodController>(
|
||||
unified_system_tray_controller_);
|
||||
|
||||
auto tile_container = std::make_unique<views::View>();
|
||||
// Sets the ID for testing.
|
||||
tile_container->SetID(VIEW_ID_QS_DISPLAY_TILE_CONTAINER);
|
||||
tile_container->AddChildView(night_light_controller->CreateTile());
|
||||
tile_container->AddChildView(dark_mode_controller->CreateTile());
|
||||
|
||||
// Transfers the ownership so the controllers won't die while the page is
|
||||
// open.
|
||||
feature_tile_controllers_.push_back(std::move(night_light_controller));
|
||||
feature_tile_controllers_.push_back(std::move(dark_mode_controller));
|
||||
|
||||
auto* tile_layout =
|
||||
tile_container->SetLayoutManager(std::make_unique<views::FlexLayout>());
|
||||
tile_layout->SetDefault(views::kMarginsKey, kTileMargin);
|
||||
|
||||
scroll_content()->AddChildView(std::move(tile_container));
|
||||
|
||||
brightness_slider_controller_ =
|
||||
std::make_unique<UnifiedBrightnessSliderController>(
|
||||
Shell::GetPrimaryRootWindowController()
|
||||
->GetStatusAreaWidget()
|
||||
->unified_system_tray()
|
||||
->model(),
|
||||
views::Button::PressedCallback());
|
||||
auto unified_brightness_view =
|
||||
brightness_slider_controller_->CreateBrightnessSlider();
|
||||
// Sets the ID for testing.
|
||||
unified_brightness_view->SetID(VIEW_ID_QS_DISPLAY_BRIGHTNESS_SLIDER);
|
||||
unified_brightness_view->slider()->SetBorder(
|
||||
views::CreateEmptyBorder(kSliderBorder));
|
||||
auto* slider_layout = unified_brightness_view->SetLayoutManager(
|
||||
std::make_unique<views::BoxLayout>(
|
||||
views::BoxLayout::Orientation::kHorizontal, kSliderPadding,
|
||||
/*between_child_spacing=*/0));
|
||||
slider_layout->SetFlexForView(unified_brightness_view->slider()->parent(),
|
||||
/*flex=*/1);
|
||||
scroll_content()->AddChildView(std::move(unified_brightness_view));
|
||||
// Sets the ID for testing.
|
||||
scroll_content()->SetID(VIEW_ID_QS_DISPLAY_SCROLL_CONTENT);
|
||||
}
|
||||
|
||||
DisplayDetailedView::~DisplayDetailedView() = default;
|
||||
|
||||
views::View* DisplayDetailedView::GetScrollContentForTest() {
|
||||
// Provides access to the protected scroll_content() in the base class.
|
||||
return scroll_content();
|
||||
}
|
||||
|
||||
void DisplayDetailedView::CreateTitleSettingsButton() {
|
||||
DCHECK(!settings_button_);
|
||||
|
||||
tri_view()->SetContainerVisible(TriView::Container::END, /*visible=*/true);
|
||||
|
||||
settings_button_ = CreateSettingsButton(
|
||||
base::BindRepeating(&DisplayDetailedView::OnSettingsClicked,
|
||||
weak_factory_.GetWeakPtr()),
|
||||
IDS_ASH_STATUS_TRAY_NIGHT_LIGHT_SETTINGS_TOOLTIP);
|
||||
settings_button_->SetState(TrayPopupUtils::CanOpenWebUISettings()
|
||||
? views::Button::STATE_NORMAL
|
||||
: views::Button::STATE_DISABLED);
|
||||
tri_view()->AddView(TriView::Container::END, settings_button_);
|
||||
}
|
||||
|
||||
void DisplayDetailedView::OnSettingsClicked() {
|
||||
if (TrayPopupUtils::CanOpenWebUISettings()) {
|
||||
CloseBubble();
|
||||
Shell::Get()->system_tray_model()->client()->ShowDisplaySettings();
|
||||
}
|
||||
}
|
||||
|
||||
BEGIN_METADATA(DisplayDetailedView, views::View)
|
||||
END_METADATA
|
||||
|
||||
} // namespace ash
|
65
ash/system/brightness/display_detailed_view.h
Normal file
65
ash/system/brightness/display_detailed_view.h
Normal file
@ -0,0 +1,65 @@
|
||||
// Copyright 2023 The Chromium Authors
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
#ifndef ASH_SYSTEM_BRIGHTNESS_DISPLAY_DETAILED_VIEW_H_
|
||||
#define ASH_SYSTEM_BRIGHTNESS_DISPLAY_DETAILED_VIEW_H_
|
||||
|
||||
#include <memory>
|
||||
|
||||
#include "ash/ash_export.h"
|
||||
#include "ash/system/tray/tray_detailed_view.h"
|
||||
#include "ui/base/metadata/metadata_header_macros.h"
|
||||
|
||||
namespace views {
|
||||
class View;
|
||||
} // namespace views
|
||||
|
||||
namespace ash {
|
||||
|
||||
class UnifiedBrightnessSliderController;
|
||||
class UnifiedSystemTrayController;
|
||||
class FeaturePodControllerBase;
|
||||
|
||||
// The detailed view to show when the drill-in button next to the brightness
|
||||
// slider is clicked. This view contains a night light feature tile, a dark mode
|
||||
// feature tile, and a brightness slider.
|
||||
class ASH_EXPORT DisplayDetailedView : public TrayDetailedView {
|
||||
public:
|
||||
METADATA_HEADER(DisplayDetailedView);
|
||||
|
||||
DisplayDetailedView(DetailedViewDelegate* delegate,
|
||||
UnifiedSystemTrayController* tray_controller);
|
||||
DisplayDetailedView(const DisplayDetailedView&) = delete;
|
||||
DisplayDetailedView& operator=(const DisplayDetailedView&) = delete;
|
||||
~DisplayDetailedView() override;
|
||||
|
||||
views::View* GetScrollContentForTest();
|
||||
|
||||
private:
|
||||
// Creates the `settings_button_` on the right end of the title row.
|
||||
void CreateTitleSettingsButton();
|
||||
|
||||
// Callback of the `settings_button_` to open the display system settings
|
||||
// page.
|
||||
void OnSettingsClicked();
|
||||
|
||||
std::unique_ptr<UnifiedBrightnessSliderController>
|
||||
brightness_slider_controller_;
|
||||
UnifiedSystemTrayController* const unified_system_tray_controller_;
|
||||
|
||||
// The vector of `FeaturePodControllerBase`. This is needed to store the
|
||||
// controllers of both tiles so that the controllers exist while the page is
|
||||
// open.
|
||||
std::vector<std::unique_ptr<FeaturePodControllerBase>>
|
||||
feature_tile_controllers_;
|
||||
|
||||
// Owned by the views hierarchy.
|
||||
views::Button* settings_button_ = nullptr;
|
||||
|
||||
base::WeakPtrFactory<DisplayDetailedView> weak_factory_{this};
|
||||
};
|
||||
|
||||
} // namespace ash
|
||||
|
||||
#endif // ASH_SYSTEM_BRIGHTNESS_DISPLAY_DETAILED_VIEW_H_
|
76
ash/system/brightness/display_detailed_view_unittest.cc
Normal file
76
ash/system/brightness/display_detailed_view_unittest.cc
Normal file
@ -0,0 +1,76 @@
|
||||
// Copyright 2023 The Chromium Authors
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
#include "ash/system/brightness/display_detailed_view.h"
|
||||
|
||||
#include <memory>
|
||||
#include <vector>
|
||||
|
||||
#include "ash/constants/ash_features.h"
|
||||
#include "ash/public/cpp/ash_view_ids.h"
|
||||
#include "ash/system/tray/detailed_view_delegate.h"
|
||||
#include "ash/system/tray/fake_detailed_view_delegate.h"
|
||||
#include "ash/test/ash_test_base.h"
|
||||
#include "base/test/scoped_feature_list.h"
|
||||
#include "ui/views/widget/widget.h"
|
||||
|
||||
namespace ash {
|
||||
namespace {
|
||||
|
||||
class DisplayDetailedViewTest : public AshTestBase {
|
||||
public:
|
||||
void SetUp() override {
|
||||
feature_list_.InitWithFeatures({features::kQsRevamp}, {});
|
||||
AshTestBase::SetUp();
|
||||
|
||||
// Create a widget so tests can click on views.
|
||||
widget_ = CreateFramelessTestWidget();
|
||||
widget_->SetFullscreen(true);
|
||||
delegate_ = std::make_unique<FakeDetailedViewDelegate>();
|
||||
// Passes in a fake delegate and a nullptr as `tray_controller` since we
|
||||
// don't need to test the actual functionality of controllers.
|
||||
detailed_view_ =
|
||||
widget_->SetContentsView(std::make_unique<DisplayDetailedView>(
|
||||
delegate_.get(), /*tray_controller=*/nullptr));
|
||||
}
|
||||
|
||||
void TearDown() override {
|
||||
widget_.reset();
|
||||
detailed_view_ = nullptr;
|
||||
delegate_.reset();
|
||||
AshTestBase::TearDown();
|
||||
}
|
||||
|
||||
base::test::ScopedFeatureList feature_list_;
|
||||
std::unique_ptr<views::Widget> widget_;
|
||||
std::unique_ptr<DetailedViewDelegate> delegate_;
|
||||
DisplayDetailedView* detailed_view_ = nullptr;
|
||||
};
|
||||
|
||||
TEST_F(DisplayDetailedViewTest, ScrollContentChildren) {
|
||||
// The scroll content has two children, one feature tile container and one
|
||||
// `UnifiedBrightnessView`.
|
||||
views::View* scroll_content =
|
||||
detailed_view_->GetViewByID(VIEW_ID_QS_DISPLAY_SCROLL_CONTENT);
|
||||
ASSERT_TRUE(scroll_content);
|
||||
ASSERT_EQ(scroll_content->children().size(), 2u);
|
||||
|
||||
// The first child of scroll content is the `tile_container`, which has two
|
||||
// children (night light and dark mode feature tiles).
|
||||
views::View* tile_container =
|
||||
scroll_content->GetViewByID(VIEW_ID_QS_DISPLAY_TILE_CONTAINER);
|
||||
ASSERT_TRUE(tile_container);
|
||||
ASSERT_EQ(tile_container->children().size(), 2u);
|
||||
EXPECT_STREQ(tile_container->children()[0]->GetClassName(), "FeatureTile");
|
||||
EXPECT_STREQ(tile_container->children()[1]->GetClassName(), "FeatureTile");
|
||||
|
||||
// The second children of scroll content is the `UnifiedBrightnessView`.
|
||||
views::View* unified_brightness_view =
|
||||
scroll_content->GetViewByID(VIEW_ID_QS_DISPLAY_BRIGHTNESS_SLIDER);
|
||||
EXPECT_STREQ(unified_brightness_view->GetClassName(),
|
||||
"UnifiedBrightnessView");
|
||||
}
|
||||
|
||||
} // namespace
|
||||
} // namespace ash
|
@ -0,0 +1,35 @@
|
||||
// Copyright 2023 The Chromium Authors
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
#include "ash/system/brightness/quick_settings_display_detailed_view_controller.h"
|
||||
|
||||
#include "ash/strings/grit/ash_strings.h"
|
||||
#include "ash/system/brightness/display_detailed_view.h"
|
||||
#include "ash/system/tray/detailed_view_delegate.h"
|
||||
#include "ui/base/l10n/l10n_util.h"
|
||||
|
||||
namespace ash {
|
||||
|
||||
QuickSettingsDisplayDetailedViewController::
|
||||
QuickSettingsDisplayDetailedViewController(
|
||||
UnifiedSystemTrayController* tray_controller)
|
||||
: detailed_view_delegate_(
|
||||
std::make_unique<DetailedViewDelegate>(tray_controller)),
|
||||
tray_controller_(tray_controller) {}
|
||||
|
||||
QuickSettingsDisplayDetailedViewController::
|
||||
~QuickSettingsDisplayDetailedViewController() = default;
|
||||
|
||||
std::unique_ptr<views::View>
|
||||
QuickSettingsDisplayDetailedViewController::CreateView() {
|
||||
return std::make_unique<DisplayDetailedView>(detailed_view_delegate_.get(),
|
||||
tray_controller_);
|
||||
}
|
||||
|
||||
std::u16string QuickSettingsDisplayDetailedViewController::GetAccessibleName()
|
||||
const {
|
||||
return l10n_util::GetStringUTF16(IDS_ASH_STATUS_TRAY_DISPLAY);
|
||||
}
|
||||
|
||||
} // namespace ash
|
@ -0,0 +1,44 @@
|
||||
// Copyright 2023 The Chromium Authors
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
#ifndef ASH_SYSTEM_BRIGHTNESS_QUICK_SETTINGS_DISPLAY_DETAILED_VIEW_CONTROLLER_H_
|
||||
#define ASH_SYSTEM_BRIGHTNESS_QUICK_SETTINGS_DISPLAY_DETAILED_VIEW_CONTROLLER_H_
|
||||
|
||||
#include <memory>
|
||||
|
||||
#include "ash/ash_export.h"
|
||||
#include "ash/system/unified/detailed_view_controller.h"
|
||||
|
||||
namespace ash {
|
||||
|
||||
class DisplayDetailedView;
|
||||
class DetailedViewDelegate;
|
||||
class UnifiedSystemTrayController;
|
||||
|
||||
// Controller of `DisplayDetailedView` in `UnifiedSystemTray`.
|
||||
class ASH_EXPORT QuickSettingsDisplayDetailedViewController
|
||||
: public DetailedViewController {
|
||||
public:
|
||||
explicit QuickSettingsDisplayDetailedViewController(
|
||||
UnifiedSystemTrayController* tray_controller);
|
||||
|
||||
QuickSettingsDisplayDetailedViewController(
|
||||
const QuickSettingsDisplayDetailedViewController&) = delete;
|
||||
QuickSettingsDisplayDetailedViewController& operator=(
|
||||
const QuickSettingsDisplayDetailedViewController&) = delete;
|
||||
|
||||
~QuickSettingsDisplayDetailedViewController() override;
|
||||
|
||||
// DetailedViewController:
|
||||
std::unique_ptr<views::View> CreateView() override;
|
||||
std::u16string GetAccessibleName() const override;
|
||||
|
||||
private:
|
||||
const std::unique_ptr<DetailedViewDelegate> detailed_view_delegate_;
|
||||
UnifiedSystemTrayController* const tray_controller_;
|
||||
};
|
||||
|
||||
} // namespace ash
|
||||
|
||||
#endif // ASH_SYSTEM_BRIGHTNESS_QUICK_SETTINGS_DISPLAY_DETAILED_VIEW_CONTROLLER_H_
|
@ -4,6 +4,8 @@
|
||||
|
||||
#include "ash/system/brightness/unified_brightness_slider_controller.h"
|
||||
|
||||
#include <memory>
|
||||
|
||||
#include "ash/constants/quick_settings_catalogs.h"
|
||||
#include "ash/shell.h"
|
||||
#include "ash/system/brightness/unified_brightness_view.h"
|
||||
@ -13,16 +15,32 @@
|
||||
|
||||
namespace ash {
|
||||
|
||||
namespace {
|
||||
|
||||
// We don't let the screen brightness go lower than this when it's being
|
||||
// adjusted via the slider. Otherwise, if the user doesn't know about the
|
||||
// brightness keys, they may turn the backlight off and not know how to turn
|
||||
// it back on.
|
||||
static constexpr double kMinBrightnessPercent = 5.0;
|
||||
|
||||
} // namespace
|
||||
|
||||
UnifiedBrightnessSliderController::UnifiedBrightnessSliderController(
|
||||
scoped_refptr<UnifiedSystemTrayModel> model)
|
||||
: model_(model) {}
|
||||
scoped_refptr<UnifiedSystemTrayModel> model,
|
||||
views::Button::PressedCallback callback)
|
||||
: model_(model), callback_(callback) {}
|
||||
|
||||
UnifiedBrightnessSliderController::~UnifiedBrightnessSliderController() =
|
||||
default;
|
||||
|
||||
std::unique_ptr<UnifiedBrightnessView>
|
||||
UnifiedBrightnessSliderController::CreateBrightnessSlider() {
|
||||
return std::make_unique<UnifiedBrightnessView>(this, model_);
|
||||
}
|
||||
|
||||
views::View* UnifiedBrightnessSliderController::CreateView() {
|
||||
DCHECK(!slider_);
|
||||
slider_ = new UnifiedBrightnessView(this, model_);
|
||||
slider_ = new UnifiedBrightnessView(this, model_, callback_);
|
||||
return slider_;
|
||||
}
|
||||
|
||||
@ -48,9 +66,6 @@ void UnifiedBrightnessSliderController::SliderValueChanged(
|
||||
// we don't update the actual brightness.
|
||||
if (percent < kMinBrightnessPercent &&
|
||||
previous_percent_ < kMinBrightnessPercent) {
|
||||
// We still need to call `OnDisplayBrightnessChanged()` to update the icon
|
||||
// of the slider, we just don't update the brightness value.
|
||||
brightness_control_delegate->SetBrightnessPercent(previous_percent_, true);
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -5,6 +5,8 @@
|
||||
#ifndef ASH_SYSTEM_BRIGHTNESS_UNIFIED_BRIGHTNESS_SLIDER_CONTROLLER_H_
|
||||
#define ASH_SYSTEM_BRIGHTNESS_UNIFIED_BRIGHTNESS_SLIDER_CONTROLLER_H_
|
||||
|
||||
#include <memory>
|
||||
|
||||
#include "ash/constants/quick_settings_catalogs.h"
|
||||
#include "ash/system/unified/unified_slider_view.h"
|
||||
#include "base/memory/scoped_refptr.h"
|
||||
@ -12,12 +14,14 @@
|
||||
namespace ash {
|
||||
|
||||
class UnifiedSystemTrayModel;
|
||||
class UnifiedBrightnessView;
|
||||
|
||||
// Controller of a slider that can change display brightness.
|
||||
class UnifiedBrightnessSliderController : public UnifiedSliderListener {
|
||||
class ASH_EXPORT UnifiedBrightnessSliderController
|
||||
: public UnifiedSliderListener {
|
||||
public:
|
||||
explicit UnifiedBrightnessSliderController(
|
||||
scoped_refptr<UnifiedSystemTrayModel> model);
|
||||
UnifiedBrightnessSliderController(scoped_refptr<UnifiedSystemTrayModel> model,
|
||||
views::Button::PressedCallback callback);
|
||||
|
||||
UnifiedBrightnessSliderController(const UnifiedBrightnessSliderController&) =
|
||||
delete;
|
||||
@ -26,6 +30,10 @@ class UnifiedBrightnessSliderController : public UnifiedSliderListener {
|
||||
|
||||
~UnifiedBrightnessSliderController() override;
|
||||
|
||||
// For QsRevamp: Creates a slider view for the brightness slider in
|
||||
// `DisplayDetailedView`.
|
||||
std::unique_ptr<UnifiedBrightnessView> CreateBrightnessSlider();
|
||||
|
||||
// UnifiedSliderListener:
|
||||
views::View* CreateView() override;
|
||||
QsSliderCatalogName GetCatalogName() override;
|
||||
@ -34,14 +42,9 @@ class UnifiedBrightnessSliderController : public UnifiedSliderListener {
|
||||
float old_value,
|
||||
views::SliderChangeReason reason) override;
|
||||
|
||||
// We don't let the screen brightness go lower than this when it's being
|
||||
// adjusted via the slider. Otherwise, if the user doesn't know about the
|
||||
// brightness keys, they may turn the backlight off and not know how to turn
|
||||
// it back on.
|
||||
static constexpr double kMinBrightnessPercent = 5.0;
|
||||
|
||||
private:
|
||||
scoped_refptr<UnifiedSystemTrayModel> model_;
|
||||
views::Button::PressedCallback const callback_;
|
||||
UnifiedSliderView* slider_ = nullptr;
|
||||
|
||||
// We have to store previous manually set value because |old_value| might be
|
||||
|
@ -4,16 +4,22 @@
|
||||
|
||||
#include "ash/system/brightness/unified_brightness_view.h"
|
||||
|
||||
#include <memory>
|
||||
|
||||
#include "ash/constants/ash_features.h"
|
||||
#include "ash/resources/vector_icons/vector_icons.h"
|
||||
#include "ash/shell.h"
|
||||
#include "ash/strings/grit/ash_strings.h"
|
||||
#include "ash/style/ash_color_id.h"
|
||||
#include "ash/system/brightness/unified_brightness_slider_controller.h"
|
||||
#include "ash/system/night_light/night_light_controller_impl.h"
|
||||
#include "ash/system/tray/tray_constants.h"
|
||||
#include "base/functional/bind.h"
|
||||
#include "base/memory/scoped_refptr.h"
|
||||
#include "ui/base/l10n/l10n_util.h"
|
||||
#include "ui/base/metadata/metadata_impl_macros.h"
|
||||
#include "ui/base/models/image_model.h"
|
||||
#include "ui/chromeos/styles/cros_tokens_color_mappings.h"
|
||||
#include "ui/gfx/paint_vector_icon.h"
|
||||
#include "ui/gfx/vector_icon_types.h"
|
||||
|
||||
namespace ash {
|
||||
@ -36,25 +42,42 @@ const gfx::VectorIcon& GetBrightnessIconForLevel(float level) {
|
||||
|
||||
UnifiedBrightnessView::UnifiedBrightnessView(
|
||||
UnifiedBrightnessSliderController* controller,
|
||||
scoped_refptr<UnifiedSystemTrayModel> model)
|
||||
scoped_refptr<UnifiedSystemTrayModel> model,
|
||||
absl::optional<views::Button::PressedCallback> detailed_button_callback)
|
||||
: UnifiedSliderView(views::Button::PressedCallback(),
|
||||
controller,
|
||||
kUnifiedMenuBrightnessIcon,
|
||||
IDS_ASH_STATUS_TRAY_BRIGHTNESS),
|
||||
model_(model),
|
||||
controller_(controller) {
|
||||
night_light_controller_(Shell::Get()->night_light_controller()) {
|
||||
model_->AddObserver(this);
|
||||
|
||||
if (features::IsQsRevampEnabled()) {
|
||||
AddChildView(std::make_unique<IconButton>(
|
||||
views::Button::PressedCallback(), IconButton::Type::kMedium,
|
||||
&kUnifiedMenuNightLightOffIcon,
|
||||
IDS_ASH_STATUS_TRAY_NIGHT_LIGHT_BUTTON_LABEL,
|
||||
// For QsRevamp: This case applies to the brightness slider in the
|
||||
// `DisplayDetailedView`. If `detailed_button_callback` is not passed in,
|
||||
// both the `night_light_button_` and the drill-in button will not be added.
|
||||
if (!detailed_button_callback.has_value()) {
|
||||
OnDisplayBrightnessChanged(/*by_user=*/false);
|
||||
return;
|
||||
}
|
||||
|
||||
const bool enabled = night_light_controller_->GetEnabled();
|
||||
night_light_button_ = AddChildView(std::make_unique<IconButton>(
|
||||
base::BindRepeating(&UnifiedBrightnessView::OnNightLightButtonPressed,
|
||||
base::Unretained(this)),
|
||||
IconButton::Type::kMedium,
|
||||
enabled ? &kUnifiedMenuNightLightIcon : &kUnifiedMenuNightLightOffIcon,
|
||||
l10n_util::GetStringFUTF16(
|
||||
IDS_ASH_STATUS_TRAY_NIGHT_LIGHT_TOGGLE_TOOLTIP,
|
||||
l10n_util::GetStringUTF16(
|
||||
enabled
|
||||
? IDS_ASH_STATUS_TRAY_NIGHT_LIGHT_ENABLED_STATE_TOOLTIP
|
||||
: IDS_ASH_STATUS_TRAY_NIGHT_LIGHT_DISABLED_STATE_TOOLTIP)),
|
||||
/*is_togglable=*/true,
|
||||
/*has_border=*/true));
|
||||
AddChildView(std::make_unique<IconButton>(
|
||||
views::Button::PressedCallback(),
|
||||
features::IsQsRevampEnabled() ? IconButton::Type::kMediumFloating
|
||||
: IconButton::Type::kMedium,
|
||||
&kQuickSettingsRightArrowIcon,
|
||||
std::move(detailed_button_callback.value()),
|
||||
IconButton::Type::kMediumFloating, &kQuickSettingsRightArrowIcon,
|
||||
IDS_ASH_STATUS_TRAY_NIGHT_LIGHT_SETTINGS_TOOLTIP));
|
||||
} else {
|
||||
button()->SetEnabled(false);
|
||||
@ -65,9 +88,7 @@ UnifiedBrightnessView::UnifiedBrightnessView(
|
||||
ui::ImageModel::FromVectorIcon(kUnifiedMenuBrightnessIcon,
|
||||
kColorAshButtonIconColor));
|
||||
}
|
||||
|
||||
model_->AddObserver(this);
|
||||
OnDisplayBrightnessChanged(false /* by_user */);
|
||||
OnDisplayBrightnessChanged(/*by_user=*/false);
|
||||
}
|
||||
|
||||
UnifiedBrightnessView::~UnifiedBrightnessView() {
|
||||
@ -76,25 +97,45 @@ UnifiedBrightnessView::~UnifiedBrightnessView() {
|
||||
|
||||
void UnifiedBrightnessView::OnDisplayBrightnessChanged(bool by_user) {
|
||||
float level = model_->display_brightness();
|
||||
float slider_level = slider()->GetValue();
|
||||
|
||||
// If level is less than `kMinBrightnessPercent`, use the slider value as
|
||||
// `level` so that when the slider is at 0 point, the icon for the slider is
|
||||
// `kUnifiedMenuBrightnessLowIcon`. Otherwise `level` will remain to be
|
||||
// `kMinBrightnessPercent` and the icon cannot be updated.
|
||||
if (level * 100 <= controller_->kMinBrightnessPercent) {
|
||||
level = slider_level;
|
||||
}
|
||||
|
||||
if (features::IsQsRevampEnabled()) {
|
||||
slider_icon()->SetImage(ui::ImageModel::FromVectorIcon(
|
||||
GetBrightnessIconForLevel(level),
|
||||
cros_tokens::kCrosSysSystemOnPrimaryContainer, kQsSliderIconSize));
|
||||
}
|
||||
|
||||
SetSliderValue(level, by_user);
|
||||
}
|
||||
|
||||
void UnifiedBrightnessView::OnNightLightButtonPressed() {
|
||||
night_light_controller_->Toggle();
|
||||
|
||||
UpdateNightLightButton();
|
||||
}
|
||||
|
||||
void UnifiedBrightnessView::UpdateNightLightButton() {
|
||||
const bool enabled = night_light_controller_->GetEnabled();
|
||||
|
||||
// Updates the icon of `night_light_button_`.
|
||||
night_light_button_->SetVectorIcon(enabled ? kUnifiedMenuNightLightIcon
|
||||
: kUnifiedMenuNightLightOffIcon);
|
||||
|
||||
// Updates the tooltip of `night_light_button_`.
|
||||
std::u16string toggle_tooltip = l10n_util::GetStringUTF16(
|
||||
enabled ? IDS_ASH_STATUS_TRAY_NIGHT_LIGHT_ENABLED_STATE_TOOLTIP
|
||||
: IDS_ASH_STATUS_TRAY_NIGHT_LIGHT_DISABLED_STATE_TOOLTIP);
|
||||
night_light_button_->SetTooltipText(l10n_util::GetStringFUTF16(
|
||||
IDS_ASH_STATUS_TRAY_NIGHT_LIGHT_TOGGLE_TOOLTIP, toggle_tooltip));
|
||||
}
|
||||
|
||||
void UnifiedBrightnessView::VisibilityChanged(View* starting_from,
|
||||
bool is_visible) {
|
||||
OnDisplayBrightnessChanged(/*by_user=*/false);
|
||||
// Only updates the `night_light_button_` if in the main page.
|
||||
if (night_light_button_) {
|
||||
UpdateNightLightButton();
|
||||
}
|
||||
}
|
||||
|
||||
BEGIN_METADATA(UnifiedBrightnessView, views::View)
|
||||
END_METADATA
|
||||
|
||||
|
@ -7,15 +7,14 @@
|
||||
|
||||
#include "ash/ash_export.h"
|
||||
#include "ash/resources/vector_icons/vector_icons.h"
|
||||
#include "ash/system/brightness/unified_brightness_slider_controller.h"
|
||||
#include "ash/system/night_light/night_light_controller_impl.h"
|
||||
#include "ash/system/unified/unified_slider_view.h"
|
||||
#include "ash/system/unified/unified_system_tray_model.h"
|
||||
#include "base/memory/scoped_refptr.h"
|
||||
#include "ui/base/metadata/metadata_header_macros.h"
|
||||
|
||||
namespace ash {
|
||||
|
||||
class UnifiedBrightnessSliderController;
|
||||
|
||||
// View of a slider that can change display brightness. It observes current
|
||||
// brightness level from UnifiedSystemTrayModel.
|
||||
class ASH_EXPORT UnifiedBrightnessView
|
||||
@ -25,11 +24,11 @@ class ASH_EXPORT UnifiedBrightnessView
|
||||
METADATA_HEADER(UnifiedBrightnessView);
|
||||
|
||||
UnifiedBrightnessView(UnifiedBrightnessSliderController* controller,
|
||||
scoped_refptr<UnifiedSystemTrayModel> model);
|
||||
|
||||
scoped_refptr<UnifiedSystemTrayModel> model,
|
||||
absl::optional<views::Button::PressedCallback>
|
||||
detailed_button_callback = absl::nullopt);
|
||||
UnifiedBrightnessView(const UnifiedBrightnessView&) = delete;
|
||||
UnifiedBrightnessView& operator=(const UnifiedBrightnessView&) = delete;
|
||||
|
||||
~UnifiedBrightnessView() override;
|
||||
|
||||
// UnifiedSystemTrayModel::Observer:
|
||||
@ -45,8 +44,19 @@ class ASH_EXPORT UnifiedBrightnessView
|
||||
};
|
||||
|
||||
private:
|
||||
// Callback called when `night_light_button_` is pressed.
|
||||
void OnNightLightButtonPressed();
|
||||
|
||||
// Updates the icon and tooltip of `night_light_button_`.
|
||||
void UpdateNightLightButton();
|
||||
|
||||
// UnifiedSliderView::
|
||||
void VisibilityChanged(View* starting_from, bool is_visible) override;
|
||||
|
||||
scoped_refptr<UnifiedSystemTrayModel> model_;
|
||||
UnifiedBrightnessSliderController* const controller_;
|
||||
NightLightControllerImpl* const night_light_controller_;
|
||||
// Owned by the views hierarchy.
|
||||
IconButton* night_light_button_ = nullptr;
|
||||
};
|
||||
|
||||
} // namespace ash
|
||||
|
@ -36,12 +36,15 @@ class UnifiedBrightnessViewTest : public AshTestBase {
|
||||
controller()->brightness_slider_controller_.get();
|
||||
unified_brightness_view_ = static_cast<UnifiedBrightnessView*>(
|
||||
controller()->unified_brightness_view_);
|
||||
brightness_slider_ =
|
||||
brightness_slider_controller_->CreateBrightnessSlider();
|
||||
}
|
||||
|
||||
void TearDown() override {
|
||||
// Tests the environment tears down with the bubble closed.
|
||||
// In `UnifiedVolumeViewTest`, the environment is torn down with the bubble
|
||||
// open, so we can test both cases.
|
||||
brightness_slider_ = nullptr;
|
||||
GetPrimaryUnifiedSystemTray()->CloseBubble();
|
||||
AshTestBase::TearDown();
|
||||
}
|
||||
@ -59,6 +62,10 @@ class UnifiedBrightnessViewTest : public AshTestBase {
|
||||
return unified_brightness_view_;
|
||||
}
|
||||
|
||||
UnifiedBrightnessView* brightness_slider() {
|
||||
return brightness_slider_.get();
|
||||
}
|
||||
|
||||
views::Slider* slider() { return unified_brightness_view_->slider(); }
|
||||
|
||||
views::ImageView* slider_icon() {
|
||||
@ -72,7 +79,13 @@ class UnifiedBrightnessViewTest : public AshTestBase {
|
||||
}
|
||||
|
||||
private:
|
||||
// The `UnifiedBrightnessView` containing a `QuickSettingsSlider`, a
|
||||
// `NightLight` button, and a drill-in button.
|
||||
UnifiedBrightnessView* unified_brightness_view_ = nullptr;
|
||||
|
||||
// The `UnifiedBrightnessView` containing only a `QuickSettingsSlider`.
|
||||
std::unique_ptr<UnifiedBrightnessView> brightness_slider_ = nullptr;
|
||||
|
||||
UnifiedBrightnessSliderController* brightness_slider_controller_ = nullptr;
|
||||
base::test::ScopedFeatureList feature_list_;
|
||||
};
|
||||
@ -80,6 +93,7 @@ class UnifiedBrightnessViewTest : public AshTestBase {
|
||||
// Tests that `UnifiedBrightnessView` is made up of a `QuickSettingsSlider`, a
|
||||
// `NightLight` button, and a drill-in button that leads to the display subpage.
|
||||
TEST_F(UnifiedBrightnessViewTest, SliderButtonComponents) {
|
||||
EXPECT_EQ(unified_brightness_view()->children().size(), 3u);
|
||||
EXPECT_STREQ(
|
||||
unified_brightness_view()->children()[0]->children()[0]->GetClassName(),
|
||||
"QuickSettingsSlider");
|
||||
@ -88,10 +102,13 @@ TEST_F(UnifiedBrightnessViewTest, SliderButtonComponents) {
|
||||
auto* night_light_button =
|
||||
static_cast<IconButton*>(unified_brightness_view()->children()[1]);
|
||||
EXPECT_STREQ(night_light_button->GetClassName(), "IconButton");
|
||||
EXPECT_EQ(
|
||||
night_light_button->GetAccessibleName(),
|
||||
l10n_util::GetStringUTF16(IDS_ASH_STATUS_TRAY_NIGHT_LIGHT_BUTTON_LABEL));
|
||||
EXPECT_EQ(night_light_button->GetTooltipText(), u"Night Light");
|
||||
EXPECT_EQ(night_light_button->GetAccessibleName(),
|
||||
l10n_util::GetStringFUTF16(
|
||||
IDS_ASH_STATUS_TRAY_NIGHT_LIGHT_TOGGLE_TOOLTIP,
|
||||
l10n_util::GetStringUTF16(
|
||||
IDS_ASH_STATUS_TRAY_NIGHT_LIGHT_DISABLED_STATE_TOOLTIP)));
|
||||
EXPECT_EQ(night_light_button->GetTooltipText(),
|
||||
u"Toggle Night Light. Night Light is off.");
|
||||
|
||||
auto* display_subpage_drill_in_button =
|
||||
static_cast<IconButton*>(unified_brightness_view()->children()[2]);
|
||||
@ -106,6 +123,15 @@ TEST_F(UnifiedBrightnessViewTest, SliderButtonComponents) {
|
||||
// drill-in button.
|
||||
}
|
||||
|
||||
// Tests that `UnifiedBrightnessView` in the display subpage is made up of a
|
||||
// `QuickSettingsSlider`.
|
||||
TEST_F(UnifiedBrightnessViewTest, SliderComponent) {
|
||||
EXPECT_EQ(brightness_slider()->children().size(), 1u);
|
||||
EXPECT_STREQ(
|
||||
brightness_slider()->children()[0]->children()[0]->GetClassName(),
|
||||
"QuickSettingsSlider");
|
||||
}
|
||||
|
||||
// Tests the slider icon matches the slider level.
|
||||
TEST_F(UnifiedBrightnessViewTest, SliderIcon) {
|
||||
const float levels[] = {0.0, 0.04, 0.2, 0.25, 0.49, 0.5, 0.7, 0.75, 0.9, 1};
|
||||
@ -126,8 +152,10 @@ TEST_F(UnifiedBrightnessViewTest, SliderIcon) {
|
||||
slider_icon()->GetImageModel().GetVectorIcon().vector_icon();
|
||||
|
||||
if (level <= 0.0) {
|
||||
// The minimum level for brightness is 0.05, since `SliderValueChanged()`
|
||||
// will adjust the brightness level and set the icon accordingly.
|
||||
EXPECT_STREQ(icon->name,
|
||||
UnifiedBrightnessView::kBrightnessLevelIcons[0]->name);
|
||||
UnifiedBrightnessView::kBrightnessLevelIcons[1]->name);
|
||||
} else if (level <= 0.5) {
|
||||
EXPECT_STREQ(icon->name,
|
||||
UnifiedBrightnessView::kBrightnessLevelIcons[1]->name);
|
||||
|
@ -4,6 +4,7 @@
|
||||
|
||||
#include "ash/system/dark_mode/dark_mode_feature_pod_controller.h"
|
||||
|
||||
#include "ash/constants/ash_features.h"
|
||||
#include "ash/constants/quick_settings_catalogs.h"
|
||||
#include "ash/public/cpp/system_tray_client.h"
|
||||
#include "ash/resources/vector_icons/vector_icons.h"
|
||||
@ -14,16 +15,28 @@
|
||||
#include "ash/system/model/system_tray_model.h"
|
||||
#include "ash/system/tray/tray_popup_utils.h"
|
||||
#include "ash/system/unified/feature_pod_button.h"
|
||||
#include "ash/system/unified/feature_tile.h"
|
||||
#include "ash/system/unified/quick_settings_metrics_util.h"
|
||||
#include "base/metrics/histogram_functions.h"
|
||||
#include "ui/base/l10n/l10n_util.h"
|
||||
|
||||
namespace ash {
|
||||
|
||||
namespace {
|
||||
|
||||
bool IsVisible() {
|
||||
// TODO(minch): Add the logic for login screen.
|
||||
// Disable dark mode feature pod in OOBE since only light mode should be
|
||||
// allowed there.
|
||||
return Shell::Get()->session_controller()->IsActiveUserSessionStarted() &&
|
||||
Shell::Get()->session_controller()->GetSessionState() !=
|
||||
session_manager::SessionState::OOBE;
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
DarkModeFeaturePodController::DarkModeFeaturePodController(
|
||||
UnifiedSystemTrayController* tray_controller)
|
||||
: tray_controller_(tray_controller) {
|
||||
DCHECK(tray_controller_);
|
||||
UnifiedSystemTrayController* tray_controller) {
|
||||
DarkLightModeControllerImpl::Get()->AddObserver(this);
|
||||
}
|
||||
|
||||
@ -38,13 +51,7 @@ FeaturePodButton* DarkModeFeaturePodController::CreateButton() {
|
||||
button_->SetLabel(l10n_util::GetStringUTF16(IDS_ASH_STATUS_TRAY_DARK_THEME));
|
||||
button_->SetLabelTooltip(l10n_util::GetStringUTF16(
|
||||
IDS_ASH_STATUS_TRAY_DARK_THEME_SETTINGS_TOOLTIP));
|
||||
// TODO(minch): Add the logic for login screen.
|
||||
// Disable dark mode feature pod in OOBE since only light mode should be
|
||||
// allowed there.
|
||||
const bool visible =
|
||||
Shell::Get()->session_controller()->IsActiveUserSessionStarted() &&
|
||||
Shell::Get()->session_controller()->GetSessionState() !=
|
||||
session_manager::SessionState::OOBE;
|
||||
const bool visible = IsVisible();
|
||||
if (visible)
|
||||
TrackVisibilityUMA();
|
||||
button_->SetVisible(visible);
|
||||
@ -53,6 +60,26 @@ FeaturePodButton* DarkModeFeaturePodController::CreateButton() {
|
||||
return button_;
|
||||
}
|
||||
|
||||
std::unique_ptr<FeatureTile> DarkModeFeaturePodController::CreateTile(
|
||||
bool compact) {
|
||||
DCHECK(features::IsQsRevampEnabled());
|
||||
DCHECK(!tile_);
|
||||
auto tile = std::make_unique<FeatureTile>(
|
||||
base::BindRepeating(&DarkModeFeaturePodController::OnIconPressed,
|
||||
weak_ptr_factory_.GetWeakPtr()));
|
||||
tile_ = tile.get();
|
||||
tile_->SetVectorIcon(kUnifiedMenuDarkModeIcon);
|
||||
tile_->SetLabel(l10n_util::GetStringUTF16(IDS_ASH_STATUS_TRAY_DARK_THEME));
|
||||
const bool visible = IsVisible();
|
||||
if (visible) {
|
||||
TrackVisibilityUMA();
|
||||
}
|
||||
tile_->SetVisible(visible);
|
||||
|
||||
UpdateTile(DarkLightModeControllerImpl::Get()->IsDarkModeEnabled());
|
||||
return tile;
|
||||
}
|
||||
|
||||
QsFeatureCatalogName DarkModeFeaturePodController::GetCatalogName() {
|
||||
return QsFeatureCatalogName::kDarkMode;
|
||||
}
|
||||
@ -73,11 +100,18 @@ void DarkModeFeaturePodController::OnIconPressed() {
|
||||
}
|
||||
|
||||
void DarkModeFeaturePodController::OnLabelPressed() {
|
||||
if (features::IsQsRevampEnabled()) {
|
||||
return;
|
||||
}
|
||||
TrackDiveInUMA();
|
||||
Shell::Get()->system_tray_model()->client()->ShowDarkModeSettings();
|
||||
}
|
||||
|
||||
void DarkModeFeaturePodController::OnColorModeChanged(bool dark_mode_enabled) {
|
||||
if (features::IsQsRevampEnabled()) {
|
||||
UpdateTile(dark_mode_enabled);
|
||||
return;
|
||||
}
|
||||
UpdateButton(dark_mode_enabled);
|
||||
}
|
||||
|
||||
@ -104,4 +138,27 @@ void DarkModeFeaturePodController::UpdateButton(bool dark_mode_enabled) {
|
||||
IDS_ASH_STATUS_TRAY_DARK_THEME_TOGGLE_TOOLTIP, tooltip_state));
|
||||
}
|
||||
|
||||
void DarkModeFeaturePodController::UpdateTile(bool dark_mode_enabled) {
|
||||
tile_->SetToggled(dark_mode_enabled);
|
||||
if (Shell::Get()->dark_light_mode_controller()->GetAutoScheduleEnabled()) {
|
||||
tile_->SetSubLabel(l10n_util::GetStringUTF16(
|
||||
dark_mode_enabled
|
||||
? IDS_ASH_STATUS_TRAY_DARK_THEME_ON_STATE_AUTO_SCHEDULED
|
||||
: IDS_ASH_STATUS_TRAY_DARK_THEME_OFF_STATE_AUTO_SCHEDULED));
|
||||
} else {
|
||||
tile_->SetSubLabel(l10n_util::GetStringUTF16(
|
||||
dark_mode_enabled ? IDS_ASH_STATUS_TRAY_DARK_THEME_ON_STATE
|
||||
: IDS_ASH_STATUS_TRAY_DARK_THEME_OFF_STATE));
|
||||
}
|
||||
|
||||
std::u16string tooltip_state = l10n_util::GetStringUTF16(
|
||||
dark_mode_enabled
|
||||
? IDS_ASH_STATUS_TRAY_DARK_THEME_ENABLED_STATE_TOOLTIP
|
||||
: IDS_ASH_STATUS_TRAY_DARK_THEME_DISABLED_STATE_TOOLTIP);
|
||||
tile_->SetTooltipText(l10n_util::GetStringFUTF16(
|
||||
IDS_ASH_STATUS_TRAY_DARK_THEME_TOGGLE_TOOLTIP, tooltip_state));
|
||||
tile_->SetVectorIcon(dark_mode_enabled ? kUnifiedMenuDarkModeIcon
|
||||
: kUnifiedMenuDarkModeOffIcon);
|
||||
}
|
||||
|
||||
} // namespace ash
|
||||
|
@ -28,6 +28,7 @@ class ASH_EXPORT DarkModeFeaturePodController : public FeaturePodControllerBase,
|
||||
|
||||
// FeaturePodControllerBase:
|
||||
FeaturePodButton* CreateButton() override;
|
||||
std::unique_ptr<FeatureTile> CreateTile(bool compact = false) override;
|
||||
QsFeatureCatalogName GetCatalogName() override;
|
||||
void OnIconPressed() override;
|
||||
void OnLabelPressed() override;
|
||||
@ -38,9 +39,14 @@ class ASH_EXPORT DarkModeFeaturePodController : public FeaturePodControllerBase,
|
||||
private:
|
||||
void UpdateButton(bool dark_mode_enabled);
|
||||
|
||||
UnifiedSystemTrayController* const tray_controller_;
|
||||
// For QsRevamp:
|
||||
void UpdateTile(bool dark_mode_enabled);
|
||||
|
||||
// Owned by the views hierarchy.
|
||||
FeaturePodButton* button_ = nullptr;
|
||||
FeatureTile* tile_ = nullptr;
|
||||
|
||||
base::WeakPtrFactory<DarkModeFeaturePodController> weak_ptr_factory_{this};
|
||||
};
|
||||
|
||||
} // namespace ash
|
||||
|
@ -9,6 +9,7 @@
|
||||
#include "ash/shell.h"
|
||||
#include "ash/style/dark_light_mode_controller_impl.h"
|
||||
#include "ash/system/unified/feature_pod_button.h"
|
||||
#include "ash/system/unified/feature_tile.h"
|
||||
#include "ash/system/unified/unified_system_tray.h"
|
||||
#include "ash/system/unified/unified_system_tray_bubble.h"
|
||||
#include "ash/test/ash_test_base.h"
|
||||
@ -18,38 +19,101 @@
|
||||
|
||||
namespace ash {
|
||||
|
||||
using DarkModeFeaturePodControllerTest = AshTestBase;
|
||||
// Tests are parameterized by feature QsRevamp.
|
||||
class DarkModeFeaturePodControllerTest
|
||||
: public AshTestBase,
|
||||
public testing::WithParamInterface<bool> {
|
||||
public:
|
||||
bool IsQsRevampEnabled() const { return GetParam(); }
|
||||
|
||||
// AshTestBase:
|
||||
void SetUp() override {
|
||||
if (IsQsRevampEnabled()) {
|
||||
feature_list_.InitWithFeatures(
|
||||
{chromeos::features::kDarkLightMode, features::kQsRevamp}, {});
|
||||
} else {
|
||||
feature_list_.InitWithFeatures({chromeos::features::kDarkLightMode},
|
||||
{features::kQsRevamp});
|
||||
}
|
||||
AshTestBase::SetUp();
|
||||
|
||||
system_tray_ = GetPrimaryUnifiedSystemTray();
|
||||
system_tray_->ShowBubble();
|
||||
feature_pod_controller_ = std::make_unique<DarkModeFeaturePodController>(
|
||||
system_tray_->bubble()->unified_system_tray_controller());
|
||||
}
|
||||
|
||||
void TearDown() override {
|
||||
tile_.reset();
|
||||
button_.reset();
|
||||
feature_pod_controller_.reset();
|
||||
system_tray_->CloseBubble();
|
||||
AshTestBase::TearDown();
|
||||
}
|
||||
|
||||
void CreateButton() {
|
||||
if (IsQsRevampEnabled()) {
|
||||
tile_ = feature_pod_controller_->CreateTile();
|
||||
} else {
|
||||
button_ = base::WrapUnique(feature_pod_controller_->CreateButton());
|
||||
}
|
||||
}
|
||||
|
||||
bool IsButtonVisible() {
|
||||
return IsQsRevampEnabled() ? tile_->GetVisible() : button_->GetVisible();
|
||||
}
|
||||
|
||||
bool IsButtonToggled() {
|
||||
return IsQsRevampEnabled() ? tile_->IsToggled() : button_->IsToggled();
|
||||
}
|
||||
|
||||
void PressIcon() { feature_pod_controller_->OnIconPressed(); }
|
||||
|
||||
void PressLabel() { feature_pod_controller_->OnLabelPressed(); }
|
||||
|
||||
private:
|
||||
base::test::ScopedFeatureList feature_list_;
|
||||
std::unique_ptr<DarkModeFeaturePodController> feature_pod_controller_;
|
||||
std::unique_ptr<FeaturePodButton> button_;
|
||||
std::unique_ptr<FeatureTile> tile_;
|
||||
UnifiedSystemTray* system_tray_ = nullptr;
|
||||
};
|
||||
|
||||
INSTANTIATE_TEST_SUITE_P(QsRevamp,
|
||||
DarkModeFeaturePodControllerTest,
|
||||
testing::Bool());
|
||||
|
||||
// Tests that toggling dark mode from the system tray disables auto scheduling
|
||||
// and switches the color mode properly.
|
||||
TEST_F(DarkModeFeaturePodControllerTest, ToggleDarkMode) {
|
||||
base::test::ScopedFeatureList feature_list;
|
||||
feature_list.InitAndEnableFeature(chromeos::features::kDarkLightMode);
|
||||
TEST_P(DarkModeFeaturePodControllerTest, ToggleDarkMode) {
|
||||
CreateButton();
|
||||
EXPECT_TRUE(IsButtonVisible());
|
||||
|
||||
auto* dark_light_mode_controller = DarkLightModeControllerImpl::Get();
|
||||
dark_light_mode_controller->OnActiveUserPrefServiceChanged(
|
||||
Shell::Get()->session_controller()->GetActivePrefService());
|
||||
|
||||
UnifiedSystemTray* system_tray = GetPrimaryUnifiedSystemTray();
|
||||
system_tray->ShowBubble();
|
||||
std::unique_ptr<DarkModeFeaturePodController>
|
||||
dark_mode_feature_pod_controller =
|
||||
std::make_unique<DarkModeFeaturePodController>(
|
||||
system_tray->bubble()->unified_system_tray_controller());
|
||||
|
||||
std::unique_ptr<FeaturePodButton> button(
|
||||
dark_mode_feature_pod_controller->CreateButton());
|
||||
|
||||
// No metrics logged before clicking on any views.
|
||||
auto histogram_tester = std::make_unique<base::HistogramTester>();
|
||||
histogram_tester->ExpectTotalCount(
|
||||
"Ash.UnifiedSystemView.FeaturePod.ToggledOn",
|
||||
/*count=*/0);
|
||||
histogram_tester->ExpectTotalCount(
|
||||
"Ash.UnifiedSystemView.FeaturePod.ToggledOff",
|
||||
/*count=*/0);
|
||||
histogram_tester->ExpectTotalCount("Ash.UnifiedSystemView.FeaturePod.DiveIn",
|
||||
/*count=*/0);
|
||||
if (IsQsRevampEnabled()) {
|
||||
histogram_tester->ExpectTotalCount("Ash.QuickSettings.FeaturePod.ToggledOn",
|
||||
/*expected_count=*/0);
|
||||
histogram_tester->ExpectTotalCount(
|
||||
"Ash.QuickSettings.FeaturePod.ToggledOff",
|
||||
/*expected_count=*/0);
|
||||
histogram_tester->ExpectTotalCount("Ash.QuickSettings.FeaturePod.DiveIn",
|
||||
/*expected_count=*/0);
|
||||
} else {
|
||||
histogram_tester->ExpectTotalCount(
|
||||
"Ash.UnifiedSystemView.FeaturePod.ToggledOn",
|
||||
/*expected_count=*/0);
|
||||
histogram_tester->ExpectTotalCount(
|
||||
"Ash.UnifiedSystemView.FeaturePod.ToggledOff",
|
||||
/*expected_count=*/0);
|
||||
histogram_tester->ExpectTotalCount(
|
||||
"Ash.UnifiedSystemView.FeaturePod.DiveIn",
|
||||
/*expected_count=*/0);
|
||||
}
|
||||
|
||||
// Enable dark mode auto scheduling.
|
||||
auto* controller = Shell::Get()->dark_light_mode_controller();
|
||||
@ -58,7 +122,7 @@ TEST_F(DarkModeFeaturePodControllerTest, ToggleDarkMode) {
|
||||
|
||||
// Check that the statuses of toggle and dark mode are consistent.
|
||||
bool dark_mode_enabled = dark_light_mode_controller->IsDarkModeEnabled();
|
||||
EXPECT_EQ(dark_mode_enabled, button->IsToggled());
|
||||
EXPECT_EQ(dark_mode_enabled, IsButtonToggled());
|
||||
|
||||
// Set the init state to enabled.
|
||||
if (!dark_mode_enabled)
|
||||
@ -66,56 +130,101 @@ TEST_F(DarkModeFeaturePodControllerTest, ToggleDarkMode) {
|
||||
|
||||
// Pressing the dark mode button should disable the scheduling and switch the
|
||||
// dark mode status.
|
||||
dark_mode_feature_pod_controller->OnIconPressed();
|
||||
PressIcon();
|
||||
EXPECT_FALSE(controller->GetAutoScheduleEnabled());
|
||||
EXPECT_EQ(false, dark_light_mode_controller->IsDarkModeEnabled());
|
||||
EXPECT_EQ(false, button->IsToggled());
|
||||
histogram_tester->ExpectTotalCount(
|
||||
"Ash.UnifiedSystemView.FeaturePod.ToggledOn",
|
||||
/*count=*/0);
|
||||
histogram_tester->ExpectTotalCount(
|
||||
"Ash.UnifiedSystemView.FeaturePod.ToggledOff",
|
||||
/*count=*/1);
|
||||
histogram_tester->ExpectTotalCount("Ash.UnifiedSystemView.FeaturePod.DiveIn",
|
||||
/*count=*/0);
|
||||
histogram_tester->ExpectBucketCount(
|
||||
"Ash.UnifiedSystemView.FeaturePod.ToggledOff",
|
||||
QsFeatureCatalogName::kDarkMode,
|
||||
/*expected_count=*/1);
|
||||
EXPECT_EQ(false, IsButtonToggled());
|
||||
|
||||
// Pressing the dark mode button again should only switch the dark mode status
|
||||
// while maintaining the disabled status of scheduling.
|
||||
dark_mode_feature_pod_controller->OnIconPressed();
|
||||
if (IsQsRevampEnabled()) {
|
||||
histogram_tester->ExpectTotalCount("Ash.QuickSettings.FeaturePod.ToggledOn",
|
||||
/*expected_count=*/0);
|
||||
histogram_tester->ExpectTotalCount(
|
||||
"Ash.QuickSettings.FeaturePod.ToggledOff",
|
||||
/*expected_count=*/1);
|
||||
histogram_tester->ExpectTotalCount("Ash.QuickSettings.FeaturePod.DiveIn",
|
||||
/*expected_count=*/0);
|
||||
histogram_tester->ExpectBucketCount(
|
||||
"Ash.QuickSettings.FeaturePod.ToggledOff",
|
||||
QsFeatureCatalogName::kDarkMode,
|
||||
/*expected_count=*/1);
|
||||
} else {
|
||||
histogram_tester->ExpectTotalCount(
|
||||
"Ash.UnifiedSystemView.FeaturePod.ToggledOn",
|
||||
/*expected_count=*/0);
|
||||
histogram_tester->ExpectTotalCount(
|
||||
"Ash.UnifiedSystemView.FeaturePod.ToggledOff",
|
||||
/*expected_count=*/1);
|
||||
histogram_tester->ExpectTotalCount(
|
||||
"Ash.UnifiedSystemView.FeaturePod.DiveIn",
|
||||
/*expected_count=*/0);
|
||||
histogram_tester->ExpectBucketCount(
|
||||
"Ash.UnifiedSystemView.FeaturePod.ToggledOff",
|
||||
QsFeatureCatalogName::kDarkMode,
|
||||
/*expected_count=*/1);
|
||||
}
|
||||
|
||||
// Pressing the dark mode button again should only switch the dark mode
|
||||
// status while maintaining the disabled status of scheduling.
|
||||
PressIcon();
|
||||
EXPECT_FALSE(controller->GetAutoScheduleEnabled());
|
||||
EXPECT_EQ(true, dark_light_mode_controller->IsDarkModeEnabled());
|
||||
EXPECT_EQ(true, button->IsToggled());
|
||||
histogram_tester->ExpectTotalCount(
|
||||
"Ash.UnifiedSystemView.FeaturePod.ToggledOn",
|
||||
/*count=*/1);
|
||||
histogram_tester->ExpectTotalCount(
|
||||
"Ash.UnifiedSystemView.FeaturePod.ToggledOff",
|
||||
/*count=*/1);
|
||||
histogram_tester->ExpectTotalCount("Ash.UnifiedSystemView.FeaturePod.DiveIn",
|
||||
/*count=*/0);
|
||||
histogram_tester->ExpectBucketCount(
|
||||
"Ash.UnifiedSystemView.FeaturePod.ToggledOn",
|
||||
QsFeatureCatalogName::kDarkMode,
|
||||
/*expected_count=*/1);
|
||||
EXPECT_EQ(true, IsButtonToggled());
|
||||
|
||||
dark_mode_feature_pod_controller->OnLabelPressed();
|
||||
histogram_tester->ExpectTotalCount(
|
||||
"Ash.UnifiedSystemView.FeaturePod.ToggledOn",
|
||||
/*count=*/1);
|
||||
histogram_tester->ExpectTotalCount(
|
||||
"Ash.UnifiedSystemView.FeaturePod.ToggledOff",
|
||||
/*count=*/1);
|
||||
histogram_tester->ExpectTotalCount("Ash.UnifiedSystemView.FeaturePod.DiveIn",
|
||||
/*count=*/1);
|
||||
histogram_tester->ExpectBucketCount("Ash.UnifiedSystemView.FeaturePod.DiveIn",
|
||||
QsFeatureCatalogName::kDarkMode,
|
||||
/*expected_count=*/1);
|
||||
if (IsQsRevampEnabled()) {
|
||||
histogram_tester->ExpectTotalCount("Ash.QuickSettings.FeaturePod.ToggledOn",
|
||||
/*expected_count=*/1);
|
||||
histogram_tester->ExpectTotalCount(
|
||||
"Ash.QuickSettings.FeaturePod.ToggledOff",
|
||||
/*expected_count=*/1);
|
||||
histogram_tester->ExpectTotalCount("Ash.QuickSettings.FeaturePod.DiveIn",
|
||||
/*expected_count=*/0);
|
||||
histogram_tester->ExpectBucketCount(
|
||||
"Ash.QuickSettings.FeaturePod.ToggledOn",
|
||||
QsFeatureCatalogName::kDarkMode,
|
||||
/*expected_count=*/1);
|
||||
} else {
|
||||
histogram_tester->ExpectTotalCount(
|
||||
"Ash.UnifiedSystemView.FeaturePod.ToggledOn",
|
||||
/*expected_count=*/1);
|
||||
histogram_tester->ExpectTotalCount(
|
||||
"Ash.UnifiedSystemView.FeaturePod.ToggledOff",
|
||||
/*expected_count=*/1);
|
||||
histogram_tester->ExpectTotalCount(
|
||||
"Ash.UnifiedSystemView.FeaturePod.DiveIn",
|
||||
/*expected_count=*/0);
|
||||
histogram_tester->ExpectBucketCount(
|
||||
"Ash.UnifiedSystemView.FeaturePod.ToggledOn",
|
||||
QsFeatureCatalogName::kDarkMode,
|
||||
/*expected_count=*/1);
|
||||
}
|
||||
|
||||
system_tray->CloseBubble();
|
||||
PressLabel();
|
||||
if (IsQsRevampEnabled()) {
|
||||
histogram_tester->ExpectTotalCount("Ash.QuickSettings.FeaturePod.ToggledOn",
|
||||
/*expected_count=*/1);
|
||||
histogram_tester->ExpectTotalCount(
|
||||
"Ash.QuickSettings.FeaturePod.ToggledOff",
|
||||
/*expected_count=*/1);
|
||||
histogram_tester->ExpectTotalCount("Ash.QuickSettings.FeaturePod.DiveIn",
|
||||
/*expected_count=*/0);
|
||||
histogram_tester->ExpectBucketCount("Ash.QuickSettings.FeaturePod.DiveIn",
|
||||
QsFeatureCatalogName::kDarkMode,
|
||||
/*expected_count=*/0);
|
||||
} else {
|
||||
histogram_tester->ExpectTotalCount(
|
||||
"Ash.UnifiedSystemView.FeaturePod.ToggledOn",
|
||||
/*expected_count=*/1);
|
||||
histogram_tester->ExpectTotalCount(
|
||||
"Ash.UnifiedSystemView.FeaturePod.ToggledOff",
|
||||
/*expected_count=*/1);
|
||||
histogram_tester->ExpectTotalCount(
|
||||
"Ash.UnifiedSystemView.FeaturePod.DiveIn",
|
||||
/*expected_count=*/1);
|
||||
histogram_tester->ExpectBucketCount(
|
||||
"Ash.UnifiedSystemView.FeaturePod.DiveIn",
|
||||
QsFeatureCatalogName::kDarkMode,
|
||||
/*expected_count=*/1);
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace ash
|
||||
|
@ -5,6 +5,7 @@
|
||||
#include "ash/system/night_light/night_light_feature_pod_controller.h"
|
||||
#include <string>
|
||||
|
||||
#include "ash/constants/ash_features.h"
|
||||
#include "ash/constants/quick_settings_catalogs.h"
|
||||
#include "ash/public/cpp/system_tray_client.h"
|
||||
#include "ash/resources/vector_icons/vector_icons.h"
|
||||
@ -17,6 +18,7 @@
|
||||
#include "ash/system/night_light/night_light_controller_impl.h"
|
||||
#include "ash/system/tray/tray_popup_utils.h"
|
||||
#include "ash/system/unified/feature_pod_button.h"
|
||||
#include "ash/system/unified/feature_tile.h"
|
||||
#include "ash/system/unified/quick_settings_metrics_util.h"
|
||||
#include "ash/system/unified/unified_system_tray_controller.h"
|
||||
#include "base/i18n/time_formatting.h"
|
||||
@ -39,7 +41,6 @@ void LogUserNightLightEvent(const bool enabled) {
|
||||
NightLightFeaturePodController::NightLightFeaturePodController(
|
||||
UnifiedSystemTrayController* tray_controller)
|
||||
: tray_controller_(tray_controller) {
|
||||
DCHECK(tray_controller_);
|
||||
Shell::Get()->system_tray_model()->clock()->AddObserver(this);
|
||||
}
|
||||
|
||||
@ -65,6 +66,28 @@ FeaturePodButton* NightLightFeaturePodController::CreateButton() {
|
||||
return button_;
|
||||
}
|
||||
|
||||
std::unique_ptr<FeatureTile> NightLightFeaturePodController::CreateTile(
|
||||
bool compact) {
|
||||
DCHECK(features::IsQsRevampEnabled());
|
||||
DCHECK(!tile_);
|
||||
auto tile = std::make_unique<FeatureTile>(
|
||||
base::BindRepeating(&NightLightFeaturePodController::OnIconPressed,
|
||||
weak_factory_.GetWeakPtr()),
|
||||
/*is_togglable=*/true);
|
||||
tile_ = tile.get();
|
||||
const bool visible =
|
||||
Shell::Get()->session_controller()->ShouldEnableSettings();
|
||||
tile_->SetVisible(visible);
|
||||
if (visible) {
|
||||
TrackVisibilityUMA();
|
||||
}
|
||||
|
||||
tile_->SetLabel(
|
||||
l10n_util::GetStringUTF16(IDS_ASH_STATUS_TRAY_NIGHT_LIGHT_BUTTON_LABEL));
|
||||
UpdateTile();
|
||||
return tile;
|
||||
}
|
||||
|
||||
QsFeatureCatalogName NightLightFeaturePodController::GetCatalogName() {
|
||||
return QsFeatureCatalogName::kNightLight;
|
||||
}
|
||||
@ -76,7 +99,7 @@ void NightLightFeaturePodController::OnIconPressed() {
|
||||
|
||||
Shell::Get()->night_light_controller()->Toggle();
|
||||
LogUserNightLightEvent(Shell::Get()->night_light_controller()->GetEnabled());
|
||||
UpdateButton();
|
||||
Update();
|
||||
|
||||
if (Shell::Get()->night_light_controller()->GetEnabled()) {
|
||||
base::RecordAction(
|
||||
@ -88,6 +111,9 @@ void NightLightFeaturePodController::OnIconPressed() {
|
||||
}
|
||||
|
||||
void NightLightFeaturePodController::OnLabelPressed() {
|
||||
if (features::IsQsRevampEnabled()) {
|
||||
return;
|
||||
}
|
||||
if (TrayPopupUtils::CanOpenWebUISettings()) {
|
||||
TrackDiveInUMA();
|
||||
base::RecordAction(
|
||||
@ -98,20 +124,20 @@ void NightLightFeaturePodController::OnLabelPressed() {
|
||||
}
|
||||
|
||||
void NightLightFeaturePodController::OnDateFormatChanged() {
|
||||
UpdateButton();
|
||||
Update();
|
||||
}
|
||||
|
||||
void NightLightFeaturePodController::OnSystemClockTimeUpdated() {
|
||||
UpdateButton();
|
||||
Update();
|
||||
}
|
||||
|
||||
void NightLightFeaturePodController::OnSystemClockCanSetTimeChanged(
|
||||
bool can_set_time) {
|
||||
UpdateButton();
|
||||
Update();
|
||||
}
|
||||
|
||||
void NightLightFeaturePodController::Refresh() {
|
||||
UpdateButton();
|
||||
Update();
|
||||
}
|
||||
|
||||
const std::u16string NightLightFeaturePodController::GetPodSubLabel() {
|
||||
@ -148,6 +174,14 @@ const std::u16string NightLightFeaturePodController::GetPodSubLabel() {
|
||||
}
|
||||
}
|
||||
|
||||
void NightLightFeaturePodController::Update() {
|
||||
if (features::IsQsRevampEnabled()) {
|
||||
UpdateTile();
|
||||
return;
|
||||
}
|
||||
UpdateButton();
|
||||
}
|
||||
|
||||
void NightLightFeaturePodController::UpdateButton() {
|
||||
auto* controller = Shell::Get()->night_light_controller();
|
||||
const bool is_enabled = controller->GetEnabled();
|
||||
@ -161,4 +195,19 @@ void NightLightFeaturePodController::UpdateButton() {
|
||||
IDS_ASH_STATUS_TRAY_NIGHT_LIGHT_TOGGLE_TOOLTIP, tooltip_state));
|
||||
}
|
||||
|
||||
void NightLightFeaturePodController::UpdateTile() {
|
||||
auto* controller = Shell::Get()->night_light_controller();
|
||||
const bool is_enabled = controller->GetEnabled();
|
||||
tile_->SetToggled(is_enabled);
|
||||
tile_->SetSubLabel(GetPodSubLabel());
|
||||
|
||||
std::u16string tooltip_state = l10n_util::GetStringUTF16(
|
||||
is_enabled ? IDS_ASH_STATUS_TRAY_NIGHT_LIGHT_ENABLED_STATE_TOOLTIP
|
||||
: IDS_ASH_STATUS_TRAY_NIGHT_LIGHT_DISABLED_STATE_TOOLTIP);
|
||||
tile_->SetTooltipText(l10n_util::GetStringFUTF16(
|
||||
IDS_ASH_STATUS_TRAY_NIGHT_LIGHT_TOGGLE_TOOLTIP, tooltip_state));
|
||||
tile_->SetVectorIcon(is_enabled ? kUnifiedMenuNightLightIcon
|
||||
: kUnifiedMenuNightLightOffIcon);
|
||||
}
|
||||
|
||||
} // namespace ash
|
||||
|
@ -10,9 +10,11 @@
|
||||
#include "ash/constants/quick_settings_catalogs.h"
|
||||
#include "ash/system/model/clock_observer.h"
|
||||
#include "ash/system/unified/feature_pod_controller_base.h"
|
||||
#include "base/memory/weak_ptr.h"
|
||||
|
||||
namespace ash {
|
||||
|
||||
class FeatureTile;
|
||||
class UnifiedSystemTrayController;
|
||||
|
||||
// Controller of a feature pod button that toggles night light mode.
|
||||
@ -32,6 +34,7 @@ class ASH_EXPORT NightLightFeaturePodController
|
||||
|
||||
// FeaturePodControllerBase:
|
||||
FeaturePodButton* CreateButton() override;
|
||||
std::unique_ptr<FeatureTile> CreateTile(bool compact = false) override;
|
||||
QsFeatureCatalogName GetCatalogName() override;
|
||||
void OnIconPressed() override;
|
||||
void OnLabelPressed() override;
|
||||
@ -47,12 +50,23 @@ class ASH_EXPORT NightLightFeaturePodController
|
||||
// current status and schedule type of night light.
|
||||
const std::u16string GetPodSubLabel();
|
||||
|
||||
// For QsRevamp: Updates `button_` or `tile_` based on whether QsRevamp flag
|
||||
// is on.
|
||||
void Update();
|
||||
|
||||
// Updates the toggle state, sub label, and icon tooltip of the `button_`.
|
||||
void UpdateButton();
|
||||
|
||||
UnifiedSystemTrayController* const tray_controller_;
|
||||
// For QsRevamp: Updates the toggle state, sub label, and icon tooltip of the
|
||||
// `tile_`.
|
||||
void UpdateTile();
|
||||
|
||||
UnifiedSystemTrayController* const tray_controller_;
|
||||
// Owned by the views hierarchy.
|
||||
FeaturePodButton* button_ = nullptr;
|
||||
FeatureTile* tile_ = nullptr;
|
||||
|
||||
base::WeakPtrFactory<NightLightFeaturePodController> weak_factory_{this};
|
||||
};
|
||||
|
||||
} // namespace ash
|
||||
|
@ -3,6 +3,7 @@
|
||||
// found in the LICENSE file.
|
||||
|
||||
#include "ash/system/night_light/night_light_feature_pod_controller.h"
|
||||
#include "ash/constants/ash_features.h"
|
||||
#include "ash/constants/quick_settings_catalogs.h"
|
||||
#include "ash/session/session_controller_impl.h"
|
||||
#include "ash/shell.h"
|
||||
@ -11,6 +12,7 @@
|
||||
#include "ash/system/model/system_tray_model.h"
|
||||
#include "ash/system/night_light/night_light_controller_impl.h"
|
||||
#include "ash/system/unified/feature_pod_button.h"
|
||||
#include "ash/system/unified/feature_tile.h"
|
||||
#include "ash/system/unified/unified_system_tray.h"
|
||||
#include "ash/system/unified/unified_system_tray_bubble.h"
|
||||
#include "ash/test/ash_test_base.h"
|
||||
@ -21,75 +23,120 @@
|
||||
|
||||
namespace ash {
|
||||
|
||||
class NightLightFeaturePodControllerTest : public AshTestBase {
|
||||
class NightLightFeaturePodControllerTest
|
||||
: public AshTestBase,
|
||||
public testing::WithParamInterface<bool> {
|
||||
public:
|
||||
NightLightFeaturePodControllerTest() {
|
||||
if (IsQsRevampEnabled()) {
|
||||
feature_list_.InitWithFeatures({features::kQsRevamp}, {});
|
||||
} else {
|
||||
feature_list_.InitWithFeatures({}, {features::kQsRevamp});
|
||||
}
|
||||
}
|
||||
|
||||
bool IsQsRevampEnabled() const { return GetParam(); }
|
||||
|
||||
void SetUp() override {
|
||||
AshTestBase::SetUp();
|
||||
|
||||
UnifiedSystemTray* system_tray = GetPrimaryUnifiedSystemTray();
|
||||
system_tray->ShowBubble();
|
||||
|
||||
feature_pod_controller_ = std::make_unique<NightLightFeaturePodController>(
|
||||
system_tray->bubble()->unified_system_tray_controller());
|
||||
feature_pod_button_.reset(feature_pod_controller_->CreateButton());
|
||||
system_tray_ = GetPrimaryUnifiedSystemTray();
|
||||
system_tray_->ShowBubble();
|
||||
}
|
||||
|
||||
void TearDown() override {
|
||||
feature_pod_controller_.reset();
|
||||
feature_pod_button_.reset();
|
||||
|
||||
button_.reset();
|
||||
tile_.reset();
|
||||
controller_.reset();
|
||||
system_tray_->CloseBubble();
|
||||
AshTestBase::TearDown();
|
||||
}
|
||||
|
||||
void CreateButton() {
|
||||
controller_ = std::make_unique<NightLightFeaturePodController>(
|
||||
system_tray_->bubble()->unified_system_tray_controller());
|
||||
if (IsQsRevampEnabled()) {
|
||||
tile_ = controller_->CreateTile();
|
||||
} else {
|
||||
button_ = base::WrapUnique(controller_->CreateButton());
|
||||
}
|
||||
}
|
||||
|
||||
bool IsButtonVisible() {
|
||||
return IsQsRevampEnabled() ? tile_->GetVisible() : button_->GetVisible();
|
||||
}
|
||||
|
||||
bool IsButtonToggled() {
|
||||
return IsQsRevampEnabled() ? tile_->IsToggled() : button_->IsToggled();
|
||||
}
|
||||
|
||||
protected:
|
||||
NightLightFeaturePodController* feature_pod_controller() {
|
||||
return feature_pod_controller_.get();
|
||||
void PressIcon() { controller_->OnIconPressed(); }
|
||||
|
||||
void PressLabel() { controller_->OnLabelPressed(); }
|
||||
|
||||
const std::u16string& GetButtonLabelText() {
|
||||
if (IsQsRevampEnabled()) {
|
||||
return tile_->sub_label()->GetText();
|
||||
}
|
||||
return button_->label_button_->GetSubLabelText();
|
||||
}
|
||||
|
||||
FeaturePodButton* feature_pod_button() { return feature_pod_button_.get(); }
|
||||
|
||||
const ash::FeaturePodLabelButton* feature_pod_label_button() {
|
||||
return feature_pod_button_->label_button_;
|
||||
}
|
||||
|
||||
void PressIcon() { feature_pod_controller_->OnIconPressed(); }
|
||||
|
||||
void PressLabel() { feature_pod_controller_->OnLabelPressed(); }
|
||||
|
||||
private:
|
||||
std::unique_ptr<FeaturePodButton> feature_pod_button_;
|
||||
std::unique_ptr<NightLightFeaturePodController> feature_pod_controller_;
|
||||
base::test::ScopedFeatureList feature_list_;
|
||||
UnifiedSystemTray* system_tray_;
|
||||
std::unique_ptr<NightLightFeaturePodController> controller_;
|
||||
std::unique_ptr<FeaturePodButton> button_;
|
||||
std::unique_ptr<FeatureTile> tile_;
|
||||
};
|
||||
|
||||
INSTANTIATE_TEST_SUITE_P(QsRevamp,
|
||||
NightLightFeaturePodControllerTest,
|
||||
testing::Bool());
|
||||
|
||||
TEST_P(NightLightFeaturePodControllerTest, ButtonVisibility) {
|
||||
// The button is visible in an active session.
|
||||
CreateButton();
|
||||
EXPECT_TRUE(IsButtonVisible());
|
||||
|
||||
// The button is not visible at the lock screen.
|
||||
GetSessionControllerClient()->LockScreen();
|
||||
CreateButton();
|
||||
EXPECT_FALSE(IsButtonVisible());
|
||||
}
|
||||
|
||||
// Tests that toggling night light from the system tray switches the color
|
||||
// mode and its button label properly.
|
||||
TEST_F(NightLightFeaturePodControllerTest, Toggle) {
|
||||
TEST_P(NightLightFeaturePodControllerTest, Toggle) {
|
||||
CreateButton();
|
||||
|
||||
NightLightControllerImpl* controller = Shell::Get()->night_light_controller();
|
||||
// Check that the feature pod button and its label reflects the default
|
||||
// Night light off without any auto scheduling.
|
||||
EXPECT_FALSE(controller->GetEnabled());
|
||||
EXPECT_FALSE(feature_pod_button()->IsToggled());
|
||||
EXPECT_FALSE(IsButtonToggled());
|
||||
EXPECT_EQ(NightLightController::ScheduleType::kNone,
|
||||
controller->GetScheduleType());
|
||||
EXPECT_EQ(
|
||||
l10n_util::GetStringUTF16(IDS_ASH_STATUS_TRAY_NIGHT_LIGHT_OFF_STATE),
|
||||
feature_pod_label_button()->GetSubLabelText());
|
||||
GetButtonLabelText());
|
||||
|
||||
// Toggling the button should enable night light and update the button label
|
||||
// correctly and maintaining no scheduling.
|
||||
feature_pod_controller()->OnIconPressed();
|
||||
PressIcon();
|
||||
EXPECT_TRUE(controller->GetEnabled());
|
||||
EXPECT_TRUE(feature_pod_button()->IsToggled());
|
||||
EXPECT_TRUE(IsButtonToggled());
|
||||
EXPECT_EQ(NightLightController::ScheduleType::kNone,
|
||||
controller->GetScheduleType());
|
||||
EXPECT_EQ(l10n_util::GetStringUTF16(IDS_ASH_STATUS_TRAY_NIGHT_LIGHT_ON_STATE),
|
||||
feature_pod_label_button()->GetSubLabelText());
|
||||
GetButtonLabelText());
|
||||
}
|
||||
|
||||
// Tests that toggling sunset-to-sunrise-scheduled night light from the system
|
||||
// tray while switches the color mode temporarily and maintains the auto
|
||||
// scheduling.
|
||||
TEST_F(NightLightFeaturePodControllerTest, SunsetToSunrise) {
|
||||
TEST_P(NightLightFeaturePodControllerTest, SunsetToSunrise) {
|
||||
CreateButton();
|
||||
|
||||
// Enable sunset-to-sunrise scheduling.
|
||||
NightLightControllerImpl* controller = Shell::Get()->night_light_controller();
|
||||
controller->SetScheduleType(
|
||||
@ -105,28 +152,28 @@ TEST_F(NightLightFeaturePodControllerTest, SunsetToSunrise) {
|
||||
// Pressing the night light button should switch the status but keep
|
||||
// sunset-to-sunrise scheduling.
|
||||
bool enabled = controller->GetEnabled();
|
||||
feature_pod_controller()->OnIconPressed();
|
||||
PressIcon();
|
||||
EXPECT_EQ(NightLightController::ScheduleType::kSunsetToSunrise,
|
||||
controller->GetScheduleType());
|
||||
EXPECT_EQ(!enabled, controller->GetEnabled());
|
||||
EXPECT_EQ(!enabled, feature_pod_button()->IsToggled());
|
||||
EXPECT_EQ(!enabled ? sublabel_on : sublabel_off,
|
||||
feature_pod_label_button()->GetSubLabelText());
|
||||
EXPECT_EQ(!enabled, IsButtonToggled());
|
||||
EXPECT_EQ(!enabled ? sublabel_on : sublabel_off, GetButtonLabelText());
|
||||
|
||||
// Pressing the night light button should switch the status but keep
|
||||
// sunset-to-sunrise scheduling.
|
||||
feature_pod_controller()->OnIconPressed();
|
||||
PressIcon();
|
||||
EXPECT_EQ(NightLightController::ScheduleType::kSunsetToSunrise,
|
||||
controller->GetScheduleType());
|
||||
EXPECT_EQ(enabled, controller->GetEnabled());
|
||||
EXPECT_EQ(enabled, feature_pod_button()->IsToggled());
|
||||
EXPECT_EQ(enabled ? sublabel_on : sublabel_off,
|
||||
feature_pod_label_button()->GetSubLabelText());
|
||||
EXPECT_EQ(enabled, IsButtonToggled());
|
||||
EXPECT_EQ(enabled ? sublabel_on : sublabel_off, GetButtonLabelText());
|
||||
}
|
||||
|
||||
// Tests that custom-scheduled night light displays the right custom start or
|
||||
// end time for custom schedule type on the button label of the system tray.
|
||||
TEST_F(NightLightFeaturePodControllerTest, Custom) {
|
||||
TEST_P(NightLightFeaturePodControllerTest, Custom) {
|
||||
CreateButton();
|
||||
|
||||
// Enable custom scheduling.
|
||||
NightLightControllerImpl* controller = Shell::Get()->night_light_controller();
|
||||
controller->SetScheduleType(NightLightController::ScheduleType::kCustom);
|
||||
@ -151,98 +198,167 @@ TEST_F(NightLightFeaturePodControllerTest, Custom) {
|
||||
// Pressing the night light button should switch the status and update the
|
||||
// label but keep the custom scheduling.
|
||||
bool enabled = controller->GetEnabled();
|
||||
feature_pod_controller()->OnIconPressed();
|
||||
PressIcon();
|
||||
EXPECT_EQ(NightLightController::ScheduleType::kCustom,
|
||||
controller->GetScheduleType());
|
||||
EXPECT_EQ(!enabled, controller->GetEnabled());
|
||||
EXPECT_EQ(!enabled, feature_pod_button()->IsToggled());
|
||||
EXPECT_EQ(!enabled ? sublabel_on : sublabel_off,
|
||||
feature_pod_label_button()->GetSubLabelText());
|
||||
EXPECT_EQ(!enabled, IsButtonToggled());
|
||||
EXPECT_EQ(!enabled ? sublabel_on : sublabel_off, GetButtonLabelText());
|
||||
|
||||
// Pressing the night light button should switch the status and update the
|
||||
// label but keep the custom scheduling.
|
||||
feature_pod_controller()->OnIconPressed();
|
||||
PressIcon();
|
||||
EXPECT_EQ(NightLightController::ScheduleType::kCustom,
|
||||
controller->GetScheduleType());
|
||||
EXPECT_EQ(enabled, controller->GetEnabled());
|
||||
EXPECT_EQ(enabled, feature_pod_button()->IsToggled());
|
||||
EXPECT_EQ(enabled ? sublabel_on : sublabel_off,
|
||||
feature_pod_label_button()->GetSubLabelText());
|
||||
EXPECT_EQ(enabled, IsButtonToggled());
|
||||
EXPECT_EQ(enabled ? sublabel_on : sublabel_off, GetButtonLabelText());
|
||||
}
|
||||
|
||||
TEST_F(NightLightFeaturePodControllerTest, IconUMATracking) {
|
||||
TEST_P(NightLightFeaturePodControllerTest, IconUMATracking) {
|
||||
CreateButton();
|
||||
|
||||
// Disable sunset-to-sunrise scheduling.
|
||||
NightLightControllerImpl* controller = Shell::Get()->night_light_controller();
|
||||
controller->SetScheduleType(NightLightController::ScheduleType::kNone);
|
||||
|
||||
// No metrics logged before clicking on any views.
|
||||
auto histogram_tester = std::make_unique<base::HistogramTester>();
|
||||
histogram_tester->ExpectTotalCount(
|
||||
"Ash.UnifiedSystemView.FeaturePod.ToggledOn",
|
||||
/*count=*/0);
|
||||
histogram_tester->ExpectTotalCount(
|
||||
"Ash.UnifiedSystemView.FeaturePod.ToggledOff",
|
||||
/*count=*/0);
|
||||
histogram_tester->ExpectTotalCount("Ash.UnifiedSystemView.FeaturePod.DiveIn",
|
||||
/*count=*/0);
|
||||
if (IsQsRevampEnabled()) {
|
||||
histogram_tester->ExpectTotalCount("Ash.QuickSettings.FeaturePod.ToggledOn",
|
||||
/*expected_count=*/0);
|
||||
histogram_tester->ExpectTotalCount(
|
||||
"Ash.QuickSettings.FeaturePod.ToggledOff",
|
||||
/*expected_count=*/0);
|
||||
histogram_tester->ExpectTotalCount("Ash.QuickSettings.FeaturePod.DiveIn",
|
||||
/*expected_count=*/0);
|
||||
} else {
|
||||
histogram_tester->ExpectTotalCount(
|
||||
"Ash.UnifiedSystemView.FeaturePod.ToggledOn",
|
||||
/*expected_count=*/0);
|
||||
histogram_tester->ExpectTotalCount(
|
||||
"Ash.UnifiedSystemView.FeaturePod.ToggledOff",
|
||||
/*expected_count=*/0);
|
||||
histogram_tester->ExpectTotalCount(
|
||||
"Ash.UnifiedSystemView.FeaturePod.DiveIn",
|
||||
/*expected_count=*/0);
|
||||
}
|
||||
|
||||
// Toggle on the nightlight feature when pressing on the icon.
|
||||
PressIcon();
|
||||
histogram_tester->ExpectTotalCount(
|
||||
"Ash.UnifiedSystemView.FeaturePod.ToggledOn",
|
||||
/*count=*/1);
|
||||
histogram_tester->ExpectTotalCount(
|
||||
"Ash.UnifiedSystemView.FeaturePod.ToggledOff",
|
||||
/*count=*/0);
|
||||
histogram_tester->ExpectTotalCount("Ash.UnifiedSystemView.FeaturePod.DiveIn",
|
||||
/*count=*/0);
|
||||
histogram_tester->ExpectBucketCount(
|
||||
"Ash.UnifiedSystemView.FeaturePod.ToggledOn",
|
||||
QsFeatureCatalogName::kNightLight,
|
||||
/*expected_count=*/1);
|
||||
if (IsQsRevampEnabled()) {
|
||||
histogram_tester->ExpectTotalCount("Ash.QuickSettings.FeaturePod.ToggledOn",
|
||||
/*expected_count=*/1);
|
||||
histogram_tester->ExpectTotalCount(
|
||||
"Ash.QuickSettings.FeaturePod.ToggledOff",
|
||||
/*expected_count=*/0);
|
||||
histogram_tester->ExpectTotalCount("Ash.QuickSettings.FeaturePod.DiveIn",
|
||||
/*expected_count=*/0);
|
||||
histogram_tester->ExpectBucketCount(
|
||||
"Ash.QuickSettings.FeaturePod.ToggledOn",
|
||||
QsFeatureCatalogName::kNightLight,
|
||||
/*expected_count=*/1);
|
||||
} else {
|
||||
histogram_tester->ExpectTotalCount(
|
||||
"Ash.UnifiedSystemView.FeaturePod.ToggledOn",
|
||||
/*expected_count=*/1);
|
||||
histogram_tester->ExpectTotalCount(
|
||||
"Ash.UnifiedSystemView.FeaturePod.ToggledOff",
|
||||
/*expected_count=*/0);
|
||||
histogram_tester->ExpectTotalCount(
|
||||
"Ash.UnifiedSystemView.FeaturePod.DiveIn",
|
||||
/*expected_count=*/0);
|
||||
histogram_tester->ExpectBucketCount(
|
||||
"Ash.UnifiedSystemView.FeaturePod.ToggledOn",
|
||||
QsFeatureCatalogName::kNightLight,
|
||||
/*expected_count=*/1);
|
||||
}
|
||||
|
||||
// Toggle off the nightlight feature when pressing on the icon again.
|
||||
PressIcon();
|
||||
histogram_tester->ExpectTotalCount(
|
||||
"Ash.UnifiedSystemView.FeaturePod.ToggledOn",
|
||||
/*count=*/1);
|
||||
histogram_tester->ExpectTotalCount(
|
||||
"Ash.UnifiedSystemView.FeaturePod.ToggledOff",
|
||||
/*count=*/1);
|
||||
histogram_tester->ExpectTotalCount("Ash.UnifiedSystemView.FeaturePod.DiveIn",
|
||||
/*count=*/0);
|
||||
histogram_tester->ExpectBucketCount(
|
||||
"Ash.UnifiedSystemView.FeaturePod.ToggledOff",
|
||||
QsFeatureCatalogName::kNightLight,
|
||||
/*expected_count=*/1);
|
||||
if (IsQsRevampEnabled()) {
|
||||
histogram_tester->ExpectTotalCount("Ash.QuickSettings.FeaturePod.ToggledOn",
|
||||
/*expected_count=*/1);
|
||||
histogram_tester->ExpectTotalCount(
|
||||
"Ash.QuickSettings.FeaturePod.ToggledOff",
|
||||
/*expected_count=*/1);
|
||||
histogram_tester->ExpectTotalCount("Ash.QuickSettings.FeaturePod.DiveIn",
|
||||
/*expected_count=*/0);
|
||||
histogram_tester->ExpectBucketCount(
|
||||
"Ash.QuickSettings.FeaturePod.ToggledOff",
|
||||
QsFeatureCatalogName::kNightLight,
|
||||
/*expected_count=*/1);
|
||||
} else {
|
||||
histogram_tester->ExpectTotalCount(
|
||||
"Ash.UnifiedSystemView.FeaturePod.ToggledOn",
|
||||
/*expected_count=*/1);
|
||||
histogram_tester->ExpectTotalCount(
|
||||
"Ash.UnifiedSystemView.FeaturePod.ToggledOff",
|
||||
/*expected_count=*/1);
|
||||
histogram_tester->ExpectTotalCount(
|
||||
"Ash.UnifiedSystemView.FeaturePod.DiveIn",
|
||||
/*expected_count=*/0);
|
||||
histogram_tester->ExpectBucketCount(
|
||||
"Ash.UnifiedSystemView.FeaturePod.ToggledOff",
|
||||
QsFeatureCatalogName::kNightLight,
|
||||
/*expected_count=*/1);
|
||||
}
|
||||
}
|
||||
|
||||
TEST_F(NightLightFeaturePodControllerTest, LabelUMATracking) {
|
||||
TEST_P(NightLightFeaturePodControllerTest, LabelUMATracking) {
|
||||
CreateButton();
|
||||
|
||||
// No metrics logged before clicking on any views.
|
||||
auto histogram_tester = std::make_unique<base::HistogramTester>();
|
||||
histogram_tester->ExpectTotalCount(
|
||||
"Ash.UnifiedSystemView.FeaturePod.ToggledOn",
|
||||
/*count=*/0);
|
||||
histogram_tester->ExpectTotalCount(
|
||||
"Ash.UnifiedSystemView.FeaturePod.ToggledOff",
|
||||
/*count=*/0);
|
||||
histogram_tester->ExpectTotalCount("Ash.UnifiedSystemView.FeaturePod.DiveIn",
|
||||
/*count=*/0);
|
||||
if (IsQsRevampEnabled()) {
|
||||
histogram_tester->ExpectTotalCount("Ash.QuickSettings.FeaturePod.ToggledOn",
|
||||
/*expected_count=*/0);
|
||||
histogram_tester->ExpectTotalCount(
|
||||
"Ash.QuickSettings.FeaturePod.ToggledOff",
|
||||
/*expected_count=*/0);
|
||||
histogram_tester->ExpectTotalCount("Ash.QuickSettings.FeaturePod.DiveIn",
|
||||
/*expected_count=*/0);
|
||||
} else {
|
||||
histogram_tester->ExpectTotalCount(
|
||||
"Ash.UnifiedSystemView.FeaturePod.ToggledOn",
|
||||
/*expected_count=*/0);
|
||||
histogram_tester->ExpectTotalCount(
|
||||
"Ash.UnifiedSystemView.FeaturePod.ToggledOff",
|
||||
/*expected_count=*/0);
|
||||
histogram_tester->ExpectTotalCount(
|
||||
"Ash.UnifiedSystemView.FeaturePod.DiveIn",
|
||||
/*expected_count=*/0);
|
||||
}
|
||||
|
||||
// Show nightlight detailed view (settings window) when pressing on the
|
||||
// label.
|
||||
PressLabel();
|
||||
histogram_tester->ExpectTotalCount(
|
||||
"Ash.UnifiedSystemView.FeaturePod.ToggledOn",
|
||||
/*count=*/0);
|
||||
histogram_tester->ExpectTotalCount(
|
||||
"Ash.UnifiedSystemView.FeaturePod.ToggledOff",
|
||||
/*count=*/0);
|
||||
histogram_tester->ExpectTotalCount("Ash.UnifiedSystemView.FeaturePod.DiveIn",
|
||||
/*count=*/1);
|
||||
histogram_tester->ExpectBucketCount("Ash.UnifiedSystemView.FeaturePod.DiveIn",
|
||||
QsFeatureCatalogName::kNightLight,
|
||||
/*expected_count=*/1);
|
||||
if (IsQsRevampEnabled()) {
|
||||
histogram_tester->ExpectTotalCount("Ash.QuickSettings.FeaturePod.ToggledOn",
|
||||
/*expected_count=*/0);
|
||||
histogram_tester->ExpectTotalCount(
|
||||
"Ash.QuickSettings.FeaturePod.ToggledOff",
|
||||
/*expected_count=*/0);
|
||||
histogram_tester->ExpectTotalCount("Ash.QuickSettings.FeaturePod.DiveIn",
|
||||
/*expected_count=*/0);
|
||||
histogram_tester->ExpectBucketCount("Ash.QuickSettings.FeaturePod.DiveIn",
|
||||
QsFeatureCatalogName::kNightLight,
|
||||
/*expected_count=*/0);
|
||||
} else {
|
||||
histogram_tester->ExpectTotalCount(
|
||||
"Ash.UnifiedSystemView.FeaturePod.ToggledOn",
|
||||
/*expected_count=*/0);
|
||||
histogram_tester->ExpectTotalCount(
|
||||
"Ash.UnifiedSystemView.FeaturePod.ToggledOff",
|
||||
/*expected_count=*/0);
|
||||
histogram_tester->ExpectTotalCount(
|
||||
"Ash.UnifiedSystemView.FeaturePod.DiveIn",
|
||||
/*expected_count=*/1);
|
||||
histogram_tester->ExpectBucketCount(
|
||||
"Ash.UnifiedSystemView.FeaturePod.DiveIn",
|
||||
QsFeatureCatalogName::kNightLight,
|
||||
/*expected_count=*/1);
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace ash
|
||||
} // namespace ash
|
||||
|
@ -22,7 +22,7 @@
|
||||
#include "ash/system/tray/tray_utils.h"
|
||||
#include "ash/system/unified/unified_system_tray.h"
|
||||
#include "ash/system/unified/unified_system_tray_bubble.h"
|
||||
#include "ash/system/unified/unified_system_tray_view.h"
|
||||
#include "base/functional/bind.h"
|
||||
#include "ui/accessibility/ax_enums.mojom.h"
|
||||
#include "ui/views/border.h"
|
||||
|
||||
@ -189,6 +189,14 @@ void UnifiedSliderBubbleController::ShowBubble(SliderType slider_type) {
|
||||
return;
|
||||
}
|
||||
|
||||
// When tray bubble is already shown, the brightness slider will get shown in
|
||||
// display detailed view. Bail out if the display details are already showing
|
||||
// to avoid resetting the bubble state.
|
||||
if (slider_type == SLIDER_TYPE_DISPLAY_BRIGHTNESS && tray_->bubble() &&
|
||||
tray_->bubble()->ShowingDisplayDetailedView()) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (IsAnyMainBubbleShown()) {
|
||||
tray_->EnsureBubbleExpanded();
|
||||
|
||||
@ -279,7 +287,9 @@ void UnifiedSliderBubbleController::CreateSliderController() {
|
||||
return;
|
||||
case SLIDER_TYPE_DISPLAY_BRIGHTNESS:
|
||||
slider_controller_ = std::make_unique<UnifiedBrightnessSliderController>(
|
||||
tray_->model().get());
|
||||
tray_->model().get(),
|
||||
base::BindRepeating(&UnifiedSystemTray::ShowDisplayDetailedViewBubble,
|
||||
base::Unretained(tray_)));
|
||||
return;
|
||||
case SLIDER_TYPE_KEYBOARD_BACKLIGHT_TOGGLE:
|
||||
slider_controller_ = std::make_unique<KeyboardBacklightToggleController>(
|
||||
|
@ -379,11 +379,15 @@ void UnifiedSystemTray::ShowVolumeSliderBubble() {
|
||||
}
|
||||
|
||||
void UnifiedSystemTray::ShowAudioDetailedViewBubble() {
|
||||
// The settings menu bubble gains focus when |show_by_click| is true.
|
||||
ShowBubble();
|
||||
bubble_->ShowAudioDetailedView();
|
||||
}
|
||||
|
||||
void UnifiedSystemTray::ShowDisplayDetailedViewBubble() {
|
||||
ShowBubble();
|
||||
bubble_->ShowDisplayDetailedView();
|
||||
}
|
||||
|
||||
void UnifiedSystemTray::ShowNetworkDetailedViewBubble() {
|
||||
ShowBubble();
|
||||
bubble_->ShowNetworkDetailedView(true /* force */);
|
||||
|
@ -136,6 +136,9 @@ class ASH_EXPORT UnifiedSystemTray
|
||||
// Shows main bubble with audio settings detailed view.
|
||||
void ShowAudioDetailedViewBubble();
|
||||
|
||||
// Shows main bubble with display settings detailed view.
|
||||
void ShowDisplayDetailedViewBubble();
|
||||
|
||||
// Shows main bubble with network settings detailed view.
|
||||
void ShowNetworkDetailedViewBubble();
|
||||
|
||||
@ -247,6 +250,10 @@ class ASH_EXPORT UnifiedSystemTray
|
||||
return channel_indicator_view_;
|
||||
}
|
||||
|
||||
UnifiedSliderBubbleController* slider_bubble_controller() {
|
||||
return slider_bubble_controller_.get();
|
||||
}
|
||||
|
||||
private:
|
||||
static const base::TimeDelta kNotificationCountUpdateDelay;
|
||||
|
||||
|
@ -192,6 +192,16 @@ void UnifiedSystemTrayBubble::ShowAudioDetailedView() {
|
||||
controller_->ShowAudioDetailedView();
|
||||
}
|
||||
|
||||
void UnifiedSystemTrayBubble::ShowDisplayDetailedView() {
|
||||
if (!bubble_widget_) {
|
||||
return;
|
||||
}
|
||||
|
||||
DCHECK(unified_view_ || quick_settings_view_);
|
||||
DCHECK(controller_);
|
||||
controller_->ShowDisplayDetailedView();
|
||||
}
|
||||
|
||||
void UnifiedSystemTrayBubble::ShowCalendarView(
|
||||
calendar_metrics::CalendarViewShowSource show_source,
|
||||
calendar_metrics::CalendarEventSource event_source) {
|
||||
@ -388,6 +398,10 @@ bool UnifiedSystemTrayBubble::ShowingAudioDetailedView() const {
|
||||
return bubble_widget_ && controller_->showing_audio_detailed_view();
|
||||
}
|
||||
|
||||
bool UnifiedSystemTrayBubble::ShowingDisplayDetailedView() const {
|
||||
return bubble_widget_ && controller_->showing_display_detailed_view();
|
||||
}
|
||||
|
||||
bool UnifiedSystemTrayBubble::ShowingCalendarView() const {
|
||||
return bubble_widget_ && controller_->showing_calendar_view();
|
||||
}
|
||||
|
@ -84,6 +84,9 @@ class ASH_EXPORT UnifiedSystemTrayBubble
|
||||
// Show audio settings detailed view.
|
||||
void ShowAudioDetailedView();
|
||||
|
||||
// Show display settings detailed view.
|
||||
void ShowDisplayDetailedView();
|
||||
|
||||
// Show calendar view.
|
||||
void ShowCalendarView(calendar_metrics::CalendarViewShowSource show_source,
|
||||
calendar_metrics::CalendarEventSource event_source);
|
||||
@ -110,8 +113,10 @@ class ASH_EXPORT UnifiedSystemTrayBubble
|
||||
// Fire a notification that an accessibility event has occured on this object.
|
||||
void NotifyAccessibilityEvent(ax::mojom::Event event, bool send_native_event);
|
||||
|
||||
// Whether the bubble is currently showing audio details or calendar view.
|
||||
// Whether the bubble is currently showing audio details or display details or
|
||||
// calendar view.
|
||||
bool ShowingAudioDetailedView() const;
|
||||
bool ShowingDisplayDetailedView() const;
|
||||
bool ShowingCalendarView() const;
|
||||
|
||||
// TrayBubbleBase:
|
||||
|
@ -22,6 +22,7 @@
|
||||
#include "ash/system/audio/unified_volume_slider_controller.h"
|
||||
#include "ash/system/bluetooth/bluetooth_detailed_view_controller.h"
|
||||
#include "ash/system/bluetooth/bluetooth_feature_pod_controller.h"
|
||||
#include "ash/system/brightness/quick_settings_display_detailed_view_controller.h"
|
||||
#include "ash/system/brightness/unified_brightness_slider_controller.h"
|
||||
#include "ash/system/camera/autozoom_feature_pod_controller.h"
|
||||
#include "ash/system/cast/cast_feature_pod_controller.h"
|
||||
@ -179,7 +180,10 @@ UnifiedSystemTrayController::CreateUnifiedQuickSettingsView() {
|
||||
unified_view->AddSliderView(volume_slider_controller_->CreateView());
|
||||
|
||||
brightness_slider_controller_ =
|
||||
std::make_unique<UnifiedBrightnessSliderController>(model_);
|
||||
std::make_unique<UnifiedBrightnessSliderController>(
|
||||
model_, views::Button::PressedCallback(base::BindRepeating(
|
||||
&UnifiedSystemTrayController::ShowDisplayDetailedView,
|
||||
base::Unretained(this))));
|
||||
unified_view->AddSliderView(brightness_slider_controller_->CreateView());
|
||||
|
||||
return unified_view;
|
||||
@ -205,7 +209,10 @@ UnifiedSystemTrayController::CreateQuickSettingsView(int max_height) {
|
||||
qs_view->AddSliderView(unified_volume_view_);
|
||||
|
||||
brightness_slider_controller_ =
|
||||
std::make_unique<UnifiedBrightnessSliderController>(model_);
|
||||
std::make_unique<UnifiedBrightnessSliderController>(
|
||||
model_, views::Button::PressedCallback(base::BindRepeating(
|
||||
&UnifiedSystemTrayController::ShowDisplayDetailedView,
|
||||
base::Unretained(this))));
|
||||
unified_brightness_view_ = brightness_slider_controller_->CreateView();
|
||||
qs_view->AddSliderView(unified_brightness_view_);
|
||||
|
||||
@ -484,6 +491,12 @@ void UnifiedSystemTrayController::ShowAudioDetailedView() {
|
||||
showing_audio_detailed_view_ = true;
|
||||
}
|
||||
|
||||
void UnifiedSystemTrayController::ShowDisplayDetailedView() {
|
||||
ShowDetailedView(
|
||||
std::make_unique<QuickSettingsDisplayDetailedViewController>(this));
|
||||
showing_display_detailed_view_ = true;
|
||||
}
|
||||
|
||||
void UnifiedSystemTrayController::ShowNotifierSettingsView() {
|
||||
if (features::IsOsSettingsAppBadgingToggleEnabled()) {
|
||||
return;
|
||||
@ -506,6 +519,7 @@ void UnifiedSystemTrayController::ShowCalendarView(
|
||||
|
||||
showing_calendar_view_ = true;
|
||||
showing_audio_detailed_view_ = false;
|
||||
showing_display_detailed_view_ = false;
|
||||
|
||||
for (auto& observer : observers_) {
|
||||
observer.OnOpeningCalendarView();
|
||||
@ -526,6 +540,7 @@ void UnifiedSystemTrayController::TransitionToMainView(bool restore_focus) {
|
||||
}
|
||||
|
||||
showing_audio_detailed_view_ = false;
|
||||
showing_display_detailed_view_ = false;
|
||||
|
||||
// Transfer `detailed_view_controller_` to a scoped object, which will be
|
||||
// destroyed once it's out of this method's scope (after resetting
|
||||
@ -573,6 +588,7 @@ void UnifiedSystemTrayController::EnsureCollapsed() {
|
||||
void UnifiedSystemTrayController::EnsureExpanded() {
|
||||
if (detailed_view_controller_) {
|
||||
showing_audio_detailed_view_ = false;
|
||||
showing_display_detailed_view_ = false;
|
||||
if (features::IsQsRevampEnabled()) {
|
||||
quick_settings_view_->ResetDetailedView();
|
||||
} else {
|
||||
@ -761,6 +777,7 @@ void UnifiedSystemTrayController::ShowDetailedView(
|
||||
}
|
||||
|
||||
showing_audio_detailed_view_ = false;
|
||||
showing_display_detailed_view_ = false;
|
||||
if (features::IsQsRevampEnabled()) {
|
||||
bubble_->UpdateBubbleHeight(/*is_showing_detiled_view=*/true);
|
||||
quick_settings_view_->SetDetailedView(controller->CreateView());
|
||||
|
@ -127,6 +127,8 @@ class ASH_EXPORT UnifiedSystemTrayController
|
||||
void ShowLocaleDetailedView();
|
||||
// Show the detailed view of audio. Called from the view.
|
||||
void ShowAudioDetailedView();
|
||||
// Show the detailed view of display. Called from the view.
|
||||
void ShowDisplayDetailedView();
|
||||
// Show the detailed view of notifier settings. Called from the view.
|
||||
void ShowNotifierSettingsView();
|
||||
// Show the detailed view of media controls. Called from the view.
|
||||
@ -201,6 +203,10 @@ class ASH_EXPORT UnifiedSystemTrayController
|
||||
return showing_audio_detailed_view_;
|
||||
}
|
||||
|
||||
bool showing_display_detailed_view() const {
|
||||
return showing_display_detailed_view_;
|
||||
}
|
||||
|
||||
bool showing_calendar_view() const { return showing_calendar_view_; }
|
||||
|
||||
private:
|
||||
@ -320,6 +326,8 @@ class ASH_EXPORT UnifiedSystemTrayController
|
||||
|
||||
bool showing_audio_detailed_view_ = false;
|
||||
|
||||
bool showing_display_detailed_view_ = false;
|
||||
|
||||
bool showing_calendar_view_ = false;
|
||||
|
||||
base::ObserverList<Observer> observers_;
|
||||
|
Reference in New Issue
Block a user