0

snap-groups: Split out faster splitview toast

This moves the faster splitview dialog out of `no_windows_widget_` and
to its own `faster_splitview_widget_` (previously `settings_widget_`).
This widget contains a toast with a skip button and the settings button.

Will refactor in follow-up CLs.

Test: added
Bug: b/323199185
Change-Id: I96eb80bcd87efd57d4b6ce8373d185bb0c0a11f6
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/5255079
Reviewed-by: Ahmed Fakhry <afakhry@chromium.org>
Commit-Queue: Sophie Wen <sophiewen@chromium.org>
Cr-Commit-Position: refs/heads/main@{#1256513}
This commit is contained in:
sophiewen
2024-02-06 00:32:12 +00:00
committed by Chromium LUCI CQ
parent 1b061c2c74
commit 2df25b7f8a
8 changed files with 124 additions and 74 deletions

@ -2460,8 +2460,14 @@ Style notes:
<message name="IDS_ASH_OVERVIEW_CLOSABLE_DESK_MINIVIEW_A11Y_EXTRA_TIP" desc="The accessibility text read by screen readers for a closeable desk mini view when the close all feature is enabled.">
Press Ctrl + W to combine with <ph name="DESK_NAME">$1<ex>Desk 1</ex></ph>. Press Ctrl + Shift + W to close desk and windows.
</message>
<message name="IDS_ASH_OVERVIEW_SETTINGS_BUTTON_LABEL" translateable="false" desc="The accessible name for the Overview Settings button during faster splitscreen setup.">
Multitasking settings
<message name="IDS_ASH_OVERVIEW_SETTINGS_BUTTON_LABEL" desc="The accessible name for the Overview Settings button during faster splitscreen setup.">
Windows and desks settings
</message>
<message name="IDS_ASH_OVERVIEW_FASTER_SPLITSCREEN_TOAST" desc="The text for the Faster Splitscreen toast during faster splitscreen setup.">
Choose a window for this side
</message>
<message name="IDS_ASH_OVERVIEW_FASTER_SPLITSCREEN_TOAST_SKIP" desc="The text for the Faster Splitscreen toast skip button.">
Dismiss
</message>
<message name="IDS_ASH_OVERVIEW_WINDOW_CLOSING_A11Y_ALERT" desc="The accessibility alert read by screen readers to alert the user that a window in overview mode is closing.">
Window <ph name="WINDOW_TITILE">$1<ex>1</ex></ph> closed.

@ -0,0 +1 @@
ce88f581202f4cf5a8a4e8d84558fe072fc8b9b7

@ -0,0 +1 @@
3a66c9bf30160c6f3d1c69a5c7f2d5cd4d6a34df

@ -0,0 +1 @@
96dc0a987229a1cc73b06b126d64275a913a4434

@ -25,6 +25,7 @@
#include "ash/strings/grit/ash_strings.h"
#include "ash/style/ash_color_id.h"
#include "ash/style/icon_button.h"
#include "ash/style/system_toast_style.h"
#include "ash/system/toast/toast_manager_impl.h"
#include "ash/wallpaper/wallpaper_controller_impl.h"
#include "ash/wm/desks/default_desk_button.h"
@ -98,6 +99,7 @@
#include "ui/gfx/geometry/transform_util.h"
#include "ui/gfx/geometry/vector2d_f.h"
#include "ui/views/animation/animation_builder.h"
#include "ui/views/highlight_border.h"
#include "ui/views/view_utils.h"
#include "ui/views/widget/widget.h"
#include "ui/wm/core/coordinate_conversion.h"
@ -2032,16 +2034,17 @@ void OverviewGrid::UpdateNoWindowsWidget(bool no_items,
// 2. In faster split screen setup, the `no_windows_widget_` show to indicate
// either no windows available to pair or select a window to complete the
// window layout.
// TODO(b/307812315): Consider separating the widgets i.e. one
// `no_windows_widget_` and one `faster_splitscreen_widget_`.
const bool in_faster_split_screen_setup_session =
window_util::IsInFasterSplitScreenSetupSession(root_window_);
if ((!in_faster_split_screen_setup_session &&
(!no_items || IsShowingSavedDeskLibrary())) ||
// TODO(b/323199185): Move this to its own function.
if (window_util::IsInFasterSplitScreenSetupSession(root_window_)) {
UpdateFasterSplitViewWidget();
return;
}
if (!no_items || IsShowingSavedDeskLibrary() ||
overview_session_->enter_exit_overview_type() ==
OverviewEnterExitType::kPine) {
no_windows_widget_.reset();
settings_widget_.reset();
faster_splitview_widget_.reset();
return;
}
@ -2053,12 +2056,7 @@ void OverviewGrid::UpdateNoWindowsWidget(bool no_items,
params.vertical_padding = kNoItemsIndicatorVerticalPaddingDp;
params.rounding_dp = kNoItemsIndicatorRoundingDp;
params.preferred_height = kNoItemsIndicatorHeightDp;
if (in_faster_split_screen_setup_session) {
params.message =
no_items ? kFasterSplitScreenToastNoWindows : kFasterSplitScreenToast;
} else {
params.message = IDS_ASH_OVERVIEW_NO_RECENT_ITEMS;
}
params.message = IDS_ASH_OVERVIEW_NO_RECENT_ITEMS;
params.parent =
root_window_->GetChildById(desks_util::GetActiveDeskContainerId());
@ -2080,10 +2078,6 @@ void OverviewGrid::UpdateNoWindowsWidget(bool no_items,
}
RefreshNoWindowsWidgetBounds(/*animate=*/false);
// This must be done after we set the no windows widget bounds.
// TODO(b/323199185): Refactor all these UI component updates.
UpdateSettingsButton();
}
void OverviewGrid::RefreshNoWindowsWidgetBounds(bool animate) {
@ -2092,25 +2086,6 @@ void OverviewGrid::RefreshNoWindowsWidgetBounds(bool animate) {
const gfx::Rect grid_bounds(GetGridEffectiveBounds());
no_windows_widget_->SetBoundsCenteredIn(grid_bounds, animate);
if (window_util::IsInFasterSplitScreenSetupSession(root_window_)) {
// If there are no windows, set it in the center of the grid.
if (item_list_.empty()) {
return;
}
// Position the widget under the bottom of the last overview item, but
// centered horizontally.
const gfx::RectF last_overview_item_bounds =
item_list_.back()->target_bounds();
const int center_x =
no_windows_widget_->GetBoundsCenteredIn(grid_bounds).x();
const gfx::Point available_origin(
center_x,
last_overview_item_bounds.bottom() + kFasterSplitScreenToastSpacingDp);
no_windows_widget_->SetBounds(
gfx::Rect(available_origin,
no_windows_widget_->GetContentsView()->GetPreferredSize()));
}
}
void OverviewGrid::RefreshGridBounds(bool animate) {
@ -2447,12 +2422,6 @@ const SavedDeskLibraryView* OverviewGrid::GetSavedDeskLibraryView() const {
: nullptr;
}
const IconButton* OverviewGrid::GetSettingsButtonForTesting() const {
return settings_widget_ ? views::AsViewClass<IconButton>(
settings_widget_->GetContentsView())
: nullptr;
}
void OverviewGrid::MaybeInitDesksWidget() {
TRACE_EVENT0("ui", "OverviewGrid::MaybeInitDesksWidget");
if (!desks_util::ShouldDesksBarBeCreated() || desks_widget_)
@ -2930,47 +2899,86 @@ void OverviewGrid::CreateAndShowPine(const gfx::ImageSkia& pine_image) {
OverviewController::Get()->OnPineWidgetShown();
}
void OverviewGrid::OnSkipButtonPressed() {
// Destroys `this`.
// TODO(sophiewen): Consider adding another exit point metric.
OverviewController::Get()->EndOverview(OverviewEndAction::kKeyEscapeOrBack);
}
void OverviewGrid::OnSettingsButtonPressed() {
// Opens the OS Settings page, which causes a window activation change and
// `EndOverview()` and destroys `this`.
Shell::Get()->shell_delegate()->OpenMultitaskingSettings();
}
void OverviewGrid::UpdateSettingsButton() {
void OverviewGrid::UpdateFasterSplitViewWidget() {
if (!window_util::IsInFasterSplitScreenSetupSession(root_window_)) {
// If we weren't started by partial overview, don't show the settings
// button.
// If we weren't started by faster splitview, don't show the widget.
faster_splitview_widget_.reset();
return;
}
if (!settings_widget_) {
if (!faster_splitview_widget_) {
views::Widget::InitParams params(views::Widget::InitParams::TYPE_POPUP);
params.ownership = views::Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET;
params.parent = desks_util::GetActiveDeskContainerForRoot(root_window_);
params.name = "OverviewSettingsWidget";
params.name = "FasterSplitViewWidget";
params.init_properties_container.SetProperty(kHideInDeskMiniViewKey, true);
params.init_properties_container.SetProperty(kOverviewUiKey, true);
settings_widget_ = std::make_unique<views::Widget>(std::move(params));
faster_splitview_widget_ =
std::make_unique<views::Widget>(std::move(params));
auto* box_layout_view = faster_splitview_widget_->SetContentsView(
std::make_unique<views::BoxLayoutView>());
box_layout_view->SetOrientation(views::BoxLayout::Orientation::kHorizontal);
box_layout_view->SetBetweenChildSpacing(kSettingsButtonSpacingDp);
box_layout_view->AddChildView(std::make_unique<SystemToastStyle>(
base::BindRepeating(&OverviewGrid::OnSkipButtonPressed,
weak_ptr_factory_.GetWeakPtr()),
l10n_util::GetStringUTF16(IDS_ASH_OVERVIEW_FASTER_SPLITSCREEN_TOAST),
l10n_util::GetStringUTF16(
IDS_ASH_OVERVIEW_FASTER_SPLITSCREEN_TOAST_SKIP)));
auto* settings_button =
settings_widget_->SetContentsView(std::make_unique<IconButton>(
box_layout_view->AddChildView(std::make_unique<IconButton>(
base::BindRepeating(&OverviewGrid::OnSettingsButtonPressed,
weak_ptr_factory_.GetWeakPtr()),
IconButton::Type::kLarge, &kOverviewSettingsIcon,
IDS_ASH_OVERVIEW_SETTINGS_BUTTON_LABEL));
// TODO(b/323199185): Consider refactoring this from `SystemToastStyle`.
const int toast_height = settings_button->GetPreferredSize().height();
const float toast_corner_radius = toast_height / 2.0f;
settings_button->SetBorder(std::make_unique<views::HighlightBorder>(
toast_corner_radius,
views::HighlightBorder::Type::kHighlightBorderOnShadow));
settings_button->SetBackgroundColor(kColorAshShieldAndBase80);
faster_splitview_widget_->Show();
}
// Align the settings button with the no windows widget.
// TODO(b/323199185): Move the faster splitscreen toast to this widget.
// TODO(b/323199185): UX needs to decide where to position this.
gfx::Rect centered_bounds(GetGridEffectiveBounds());
const gfx::Size preferred_size =
faster_splitview_widget_->GetContentsView()->GetPreferredSize();
centered_bounds.ClampToCenteredSize(preferred_size);
// If there are no windows, set it in the center of the grid.
if (item_list_.empty()) {
faster_splitview_widget_->SetBounds(centered_bounds);
return;
}
// Position the widget under the bottom of the last overview item, but
// centered horizontally.
const gfx::RectF last_overview_item_bounds =
item_list_.back()->target_bounds();
centered_bounds.set_y(last_overview_item_bounds.bottom() +
kFasterSplitScreenToastSpacingDp);
faster_splitview_widget_->SetBounds(centered_bounds);
// TODO(b/323409897): Add a11y focus traversal and Chromevox support.
CHECK(no_windows_widget_);
const gfx::Rect no_windows_widget_bounds(
no_windows_widget_->GetWindowBoundsInScreen());
settings_widget_->SetBounds(
gfx::Rect(no_windows_widget_bounds.right() + kSettingsButtonSpacingDp,
no_windows_widget_bounds.y(), no_windows_widget_bounds.height(),
no_windows_widget_bounds.height()));
settings_widget_->Show();
}
} // namespace ash

@ -41,7 +41,6 @@ class PresentationTimeRecorder;
namespace ash {
class IconButton;
class LegacyDeskBarView;
class OverviewDropTarget;
class OverviewGridEventHandler;
@ -474,7 +473,9 @@ class ASH_EXPORT OverviewGrid : public SplitViewObserver,
const gfx::Rect bounds_for_testing() const { return bounds_; }
float scroll_offset_for_testing() const { return scroll_offset_; }
views::Widget* pine_widget_for_testing() const { return pine_widget_.get(); }
const IconButton* GetSettingsButtonForTesting() const;
views::Widget* faster_splitview_widget_for_testing() {
return faster_splitview_widget_.get();
}
private:
friend class DesksTemplatesTest;
@ -590,12 +591,15 @@ class ASH_EXPORT OverviewGrid : public SplitViewObserver,
// instead.
void CreateAndShowPine(const gfx::ImageSkia& pine_image);
// Called when the partial overview settings button is pressed.
// Called when the faster splitview toast skip button is pressed.
void OnSkipButtonPressed();
// Called when the faster splitview settings button is pressed.
void OnSettingsButtonPressed();
// Updates the visibility of `settings_widget_`. The widget will only be shown
// if automatic partial overview was started.
void UpdateSettingsButton();
// Updates the visibility of `faster_splitview_widget_`. The widget will
// only be shown if faster splitview setup is in session.
void UpdateFasterSplitViewWidget();
// The drop target is created when a window or overview item is being dragged,
// and is destroyed when the drag ends or overview mode is ended. The drop
@ -628,8 +632,9 @@ class ASH_EXPORT OverviewGrid : public SplitViewObserver,
// The contents view of the above |desks_widget_| if created.
raw_ptr<LegacyDeskBarView, DanglingUntriaged> desks_bar_view_ = nullptr;
// Faster splitscreen settings widget.
std::unique_ptr<views::Widget> settings_widget_;
// Widget that appears during faster splitview setup. Contains the faster
// splitview toast and the overview settings button.
std::unique_ptr<views::Widget> faster_splitview_widget_;
// True if the overview grid should animate when exiting overview mode. Note
// even if it's true, it doesn't mean all window items in the grid should

@ -18,6 +18,7 @@
#include "ash/screen_util.h"
#include "ash/shell.h"
#include "ash/style/close_button.h"
#include "ash/style/system_toast_style.h"
#include "ash/system/toast/toast_manager_impl.h"
#include "ash/test/ash_test_base.h"
#include "ash/test/ash_test_util.h"
@ -175,8 +176,9 @@ SplitViewOverviewSession* VerifySplitViewOverviewSession(
EXPECT_TRUE(work_area_bounds().Contains(expected_grid_bounds));
if (!Shell::Get()->IsInTabletMode() && faster_split_screen_setup) {
EXPECT_TRUE(
GetOverviewGridForRoot(window->GetRootWindow())->no_windows_widget());
auto* overview_grid = GetOverviewGridForRoot(window->GetRootWindow());
EXPECT_TRUE(overview_grid->faster_splitview_widget_for_testing());
EXPECT_FALSE(overview_grid->no_windows_widget());
}
return split_view_overview_session;
@ -327,8 +329,9 @@ TEST_F(FasterSplitScreenTest, Basic) {
// Enter overview normally. Test no widget.
ToggleOverview();
EXPECT_FALSE(
GetOverviewGridForRoot(w1->GetRootWindow())->no_windows_widget());
auto* overview_grid = GetOverviewGridForRoot(w1->GetRootWindow());
EXPECT_FALSE(overview_grid->no_windows_widget());
EXPECT_FALSE(overview_grid->faster_splitview_widget_for_testing());
}
TEST_F(FasterSplitScreenTest, CycleSnap) {
@ -573,6 +576,25 @@ TEST_F(FasterSplitScreenTest, SkipPairingOnKeyEvent) {
EXPECT_TRUE(Shell::Get()->window_cycle_controller()->IsCycling());
}
TEST_F(FasterSplitScreenTest, SkipPairingToast) {
std::unique_ptr<aura::Window> w1(CreateAppWindow());
std::unique_ptr<aura::Window> w2(CreateAppWindow());
SnapOneTestWindow(w1.get(), chromeos::WindowStateType::kPrimarySnapped);
VerifySplitViewOverviewSession(w1.get());
auto* overview_grid = GetOverviewGridForRoot(w1->GetRootWindow());
ASSERT_TRUE(overview_grid);
auto* faster_splitview_widget =
overview_grid->faster_splitview_widget_for_testing();
ASSERT_TRUE(faster_splitview_widget);
auto* toast_view = views::AsViewClass<SystemToastStyle>(
faster_splitview_widget->GetContentsView()->children()[0]);
ASSERT_TRUE(toast_view);
LeftClickOn(toast_view->dismiss_button());
EXPECT_FALSE(OverviewController::Get()->InOverviewSession());
}
TEST_F(FasterSplitScreenTest, DontStartPartialOverviewAfterSkippingPairing) {
std::unique_ptr<aura::Window> w1(CreateAppWindow());
std::unique_ptr<aura::Window> w2(CreateAppWindow());

@ -20,6 +20,7 @@
#include "content/public/test/test_navigation_observer.h"
#include "ui/events/test/event_generator.h"
#include "ui/views/controls/button/button.h"
#include "ui/views/view_utils.h"
namespace {
@ -76,7 +77,12 @@ IN_PROC_BROWSER_TEST_F(FasterSplitScreenBrowserTest, SnapWindowSettings) {
auto* overview_grid =
ash::OverviewController::Get()->overview_session()->GetGridWithRootWindow(
window->GetRootWindow());
auto* settings_button = overview_grid->GetSettingsButtonForTesting();
ASSERT_TRUE(overview_grid);
auto* faster_splitview_widget =
overview_grid->faster_splitview_widget_for_testing();
ASSERT_TRUE(faster_splitview_widget);
auto* settings_button = views::AsViewClass<ash::IconButton>(
faster_splitview_widget->GetContentsView()->children()[1]);
ASSERT_TRUE(settings_button);
// Setup navigation observer to wait for the OS Settings page.