#include <array>
#include <memory>
#include <string>
#include <vector>
#include "ash/accessibility/accessibility_controller.h"
#include "ash/accessibility/sticky_keys/sticky_keys_controller.h"
#include "ash/accessibility/ui/accessibility_confirmation_dialog.h"
#include "ash/app_list/app_list_controller_impl.h"
#include "ash/constants/ash_features.h"
#include "ash/constants/ash_pref_names.h"
#include "ash/display/screen_orientation_controller.h"
#include "ash/display/screen_orientation_controller_test_api.h"
#include "ash/keyboard/ui/keyboard_ui_controller.h"
#include "ash/keyboard/ui/test/keyboard_test_util.h"
#include "ash/multi_user/multi_user_window_manager.h"
#include "ash/multi_user/multi_user_window_manager_observer.h"
#include "ash/public/cpp/ash_prefs.h"
#include "ash/public/cpp/event_rewriter_controller.h"
#include "ash/public/cpp/shelf_model.h"
#include "ash/public/cpp/shelf_prefs.h"
#include "ash/public/cpp/shelf_types.h"
#include "ash/public/cpp/test/test_shelf_item_delegate.h"
#include "ash/public/cpp/window_finder.h"
#include "ash/root_window_controller.h"
#include "ash/screen_util.h"
#include "ash/session/session_controller_impl.h"
#include "ash/shelf/hotseat_widget.h"
#include "ash/shelf/scroll_arrow_view.h"
#include "ash/shelf/scrollable_shelf_view.h"
#include "ash/shelf/shelf.h"
#include "ash/shelf/shelf_layout_manager.h"
#include "ash/shelf/shelf_navigation_widget.h"
#include "ash/shelf/shelf_test_util.h"
#include "ash/shelf/shelf_view.h"
#include "ash/shelf/shelf_view_test_api.h"
#include "ash/shelf/shelf_widget.h"
#include "ash/shell.h"
#include "ash/strings/grit/ash_strings.h"
#include "ash/style/ash_color_provider.h"
#include "ash/style/close_button.h"
#include "ash/style/color_util.h"
#include "ash/test/ash_test_base.h"
#include "ash/test/ash_test_helper.h"
#include "ash/test/ash_test_util.h"
#include "ash/wm/desks/default_desk_button.h"
#include "ash/wm/desks/desk.h"
#include "ash/wm/desks/desk_action_button.h"
#include "ash/wm/desks/desk_action_context_menu.h"
#include "ash/wm/desks/desk_action_view.h"
#include "ash/wm/desks/desk_animation_base.h"
#include "ash/wm/desks/desk_bar_controller.h"
#include "ash/wm/desks/desk_bar_view_base.h"
#include "ash/wm/desks/desk_button/desk_button.h"
#include "ash/wm/desks/desk_button/desk_button_container.h"
#include "ash/wm/desks/desk_button/desk_switch_button.h"
#include "ash/wm/desks/desk_button_base.h"
#include "ash/wm/desks/desk_icon_button.h"
#include "ash/wm/desks/desk_mini_view.h"
#include "ash/wm/desks/desk_name_view.h"
#include "ash/wm/desks/desk_preview_view.h"
#include "ash/wm/desks/desk_textfield.h"
#include "ash/wm/desks/desks_controller.h"
#include "ash/wm/desks/desks_histogram_enums.h"
#include "ash/wm/desks/desks_restore_util.h"
#include "ash/wm/desks/desks_test_api.h"
#include "ash/wm/desks/desks_test_util.h"
#include "ash/wm/desks/desks_util.h"
#include "ash/wm/desks/overview_desk_bar_view.h"
#include "ash/wm/desks/root_window_desk_switch_animator_test_api.h"
#include "ash/wm/desks/scroll_arrow_button.h"
#include "ash/wm/desks/templates/saved_desk_test_helper.h"
#include "ash/wm/desks/templates/saved_desk_test_util.h"
#include "ash/wm/desks/templates/saved_desk_util.h"
#include "ash/wm/mru_window_tracker.h"
#include "ash/wm/overview/overview_controller.h"
#include "ash/wm/overview/overview_grid.h"
#include "ash/wm/overview/overview_grid_test_api.h"
#include "ash/wm/overview/overview_item.h"
#include "ash/wm/overview/overview_session.h"
#include "ash/wm/overview/overview_test_util.h"
#include "ash/wm/overview/overview_window_drag_controller.h"
#include "ash/wm/splitview/split_view_controller.h"
#include "ash/wm/splitview/split_view_drag_indicators.h"
#include "ash/wm/splitview/split_view_types.h"
#include "ash/wm/splitview/split_view_utils.h"
#include "ash/wm/tablet_mode/tablet_mode_controller_test_api.h"
#include "ash/wm/window_state.h"
#include "ash/wm/window_util.h"
#include "ash/wm/wm_event.h"
#include "ash/wm/workspace/backdrop_controller.h"
#include "ash/wm/workspace/workspace_layout_manager.h"
#include "ash/wm/workspace_controller.h"
#include "base/containers/contains.h"
#include "base/i18n/rtl.h"
#include "base/memory/raw_ptr.h"
#include "base/run_loop.h"
#include "base/scoped_observation.h"
#include "base/strings/string_number_conversions.h"
#include "base/strings/string_util.h"
#include "base/strings/stringprintf.h"
#include "base/strings/utf_string_conversions.h"
#include "base/test/bind.h"
#include "base/test/gtest_util.h"
#include "base/test/metrics/histogram_tester.h"
#include "base/test/scoped_feature_list.h"
#include "base/test/simple_test_clock.h"
#include "base/time/time.h"
#include "chromeos/components/kiosk/kiosk_test_utils.h"
#include "chromeos/constants/chromeos_features.h"
#include "chromeos/ui/frame/caption_buttons/snap_controller.h"
#include "chromeos/ui/frame/desks/move_to_desks_menu_delegate.h"
#include "chromeos/ui/frame/desks/move_to_desks_menu_model.h"
#include "chromeos/ui/wm/desks/chromeos_desks_histogram_enums.h"
#include "components/prefs/pref_service.h"
#include "components/prefs/scoped_user_pref_update.h"
#include "components/prefs/testing_pref_service.h"
#include "components/session_manager/session_manager_types.h"
#include "components/user_manager/fake_user_manager.h"
#include "components/user_manager/scoped_user_manager.h"
#include "ui/accessibility/ax_action_data.h"
#include "ui/aura/client/aura_constants.h"
#include "ui/aura/client/window_parenting_client.h"
#include "ui/aura/test/test_window_delegate.h"
#include "ui/aura/window.h"
#include "ui/aura/window_observer.h"
#include "ui/base/clipboard/clipboard_buffer.h"
#include "ui/base/clipboard/scoped_clipboard_writer.h"
#include "ui/base/ime/ash/fake_ime_keyboard.h"
#include "ui/base/mojom/ui_base_types.mojom-shared.h"
#include "ui/base/ui_base_types.h"
#include "ui/compositor/layer.h"
#include "ui/compositor/layer_animator.h"
#include "ui/compositor/test/layer_animation_stopped_waiter.h"
#include "ui/compositor_extra/shadow.h"
#include "ui/display/display.h"
#include "ui/display/display_switches.h"
#include "ui/display/screen.h"
#include "ui/display/test/display_manager_test_api.h"
#include "ui/events/ash/event_rewriter_ash.h"
#include "ui/events/ash/fake_event_rewriter_ash_delegate.h"
#include "ui/events/devices/device_data_manager.h"
#include "ui/events/devices/device_data_manager_test_api.h"
#include "ui/events/devices/input_device.h"
#include "ui/events/event_constants.h"
#include "ui/events/keycodes/keyboard_codes_posix.h"
#include "ui/events/test/event_generator.h"
#include "ui/gfx/geometry/point.h"
#include "ui/gfx/geometry/point_conversions.h"
#include "ui/gfx/geometry/point_f.h"
#include "ui/gfx/geometry/rect.h"
#include "ui/gfx/geometry/transform.h"
#include "ui/gfx/image/image_unittest_util.h"
#include "ui/gfx/scoped_animation_duration_scale_mode.h"
#include "ui/views/background.h"
#include "ui/views/controls/button/button.h"
#include "ui/views/controls/button/label_button.h"
#include "ui/views/controls/focus_ring.h"
#include "ui/views/controls/menu/menu_item_view.h"
#include "ui/views/test/test_widget_builder.h"
#include "ui/views/test/views_test_utils.h"
#include "ui/views/widget/any_widget_observer.h"
#include "ui/views/widget/widget.h"
#include "ui/views/widget/widget_delegate.h"
#include "ui/views/window/client_view.h"
#include "ui/wm/core/shadow_controller.h"
#include "ui/wm/core/window_modality_controller.h"
#include "ui/wm/core/window_util.h"
namespace ash {
class StuckWidgetDelegate : public views::WidgetDelegate {
public:
StuckWidgetDelegate() {
SetCanMaximize(true);
SetCanMinimize(true);
SetCanResize(true);
SetOwnedByWidget(OwnedByWidgetPassKey());
}
StuckWidgetDelegate(const StuckWidgetDelegate& other) = delete;
StuckWidgetDelegate& operator=(const StuckWidgetDelegate& other) = delete;
~StuckWidgetDelegate() override = default;
std::unique_ptr<views::FrameView> CreateFrameView(
views::Widget* widget) override {
return Shell::Get()->CreateDefaultFrameView(widget);
}
bool OnCloseRequested(views::Widget::ClosedReason close_reason) override {
return false;
}
};
namespace {
using ::testing::ElementsAre;
using ::testing::ElementsAreArray;
using ::testing::ValuesIn;
std::unique_ptr<aura::Window> CreateTransientWindow(
aura::Window* transient_parent,
const gfx::Rect& bounds) {
std::unique_ptr<aura::Window> window =
std::make_unique<aura::Window>(nullptr, aura::client::WINDOW_TYPE_POPUP);
window->Init(ui::LAYER_NOT_DRAWN);
window->SetBounds(bounds);
::wm::AddTransientChild(transient_parent, window.get());
aura::client::ParentWindowWithContext(window.get(),
transient_parent->GetRootWindow(),
bounds, display::kInvalidDisplayId);
window->Show();
return window;
}
std::unique_ptr<aura::Window> CreateTransientModalChildWindow(
aura::Window* transient_parent) {
auto child =
CreateTransientWindow(transient_parent, gfx::Rect(20, 30, 200, 150));
child->SetProperty(aura::client::kModalKey, ui::mojom::ModalType::kWindow);
::wm::SetModalParent(child.get(), transient_parent);
return child;
}
bool DoesActiveDeskContainWindow(aura::Window* window) {
return base::Contains(DesksController::Get()->active_desk()->windows(),
window);
}
void CloseDeskFromMiniView(DeskMiniView* desk_mini_view,
ui::test::EventGenerator* event_generator) {
DCHECK(desk_mini_view);
DeskBarViewBase* desk_bar_view = desk_mini_view->owner_bar();
const gfx::Point mini_view_center =
desk_mini_view->GetBoundsInScreen().CenterPoint();
event_generator->MoveMouseTo(mini_view_center);
const CloseButton* close_button =
GetCloseDeskButtonForMiniView(desk_mini_view);
EXPECT_TRUE(close_button->GetVisible());
event_generator->MoveMouseTo(close_button->GetBoundsInScreen().CenterPoint());
event_generator->ClickLeftButton();
views::test::RunScheduledLayout(desk_bar_view);
}
void DoubleClickOnView(const views::View* view,
ui::test::EventGenerator* event_generator) {
DCHECK(view);
const gfx::Point view_center = view->GetBoundsInScreen().CenterPoint();
event_generator->MoveMouseTo(view_center);
event_generator->DoubleClickLeftButton();
}
void SendAccessibleActionToView(views::View* view, ax::mojom::Action action) {
ui::AXActionData action_data;
action_data.action = action;
view->HandleAccessibleAction(action_data);
}
BackdropController* GetDeskBackdropController(const Desk* desk,
aura::Window* root) {
auto* workspace_controller =
GetWorkspaceController(desk->GetDeskContainerForRoot(root));
WorkspaceLayoutManager* layout_manager =
workspace_controller->layout_manager();
return layout_manager->backdrop_controller();
}
void LongTapOnDeskPreview(const DeskMiniView* desk_mini_view,
ui::test::EventGenerator* event_generator) {
DCHECK(desk_mini_view);
gfx::Point desk_preview_center =
desk_mini_view->GetPreviewBoundsInScreen().CenterPoint();
LongGestureTap(desk_preview_center, event_generator, false);
}
void StartDragDeskPreview(const DeskMiniView* desk_mini_view,
ui::test::EventGenerator* event_generator) {
DCHECK(desk_mini_view);
gfx::Point desk_preview_center =
desk_mini_view->GetPreviewBoundsInScreen().CenterPoint();
event_generator->set_current_screen_location(desk_preview_center);
event_generator->PressLeftButton();
event_generator->MoveMouseBy(0, 50);
}
template <class Predicate>
bool TabUntil(bool reverse,
Predicate&& predicate,
ui::test::EventGenerator* generator) {
for (int i = 0; i != 100; ++i) {
if (predicate()) {
return true;
}
SendKey(ui::VKEY_TAB, generator, reverse ? ui::EF_SHIFT_DOWN : ui::EF_NONE);
}
return false;
}
auto ViewFocused(views::View* view) {
return [view] { return view->HasFocus(); };
}
class TestObserver : public DesksController::Observer {
public:
TestObserver() = default;
TestObserver(const TestObserver&) = delete;
TestObserver& operator=(const TestObserver&) = delete;
~TestObserver() override = default;
const std::vector<raw_ptr<const Desk, VectorExperimental>>& desks() const {
return desks_;
}
int desk_name_changed_notify_counts() const {
return desk_name_changed_notify_counts_;
}
void OnDeskAdded(const Desk* desk, bool from_undo) override {
const size_t new_desk_index = DesksController::Get()->GetDeskIndex(desk);
if (new_desk_index > desks_.size()) {
desks_.emplace_back(desk);
} else {
desks_.insert(desks_.begin() + new_desk_index, desk);
}
EXPECT_TRUE(DesksController::Get()->AreDesksBeingModified());
}
void OnDeskRemoved(const Desk* desk) override {
std::erase(desks_, desk);
EXPECT_TRUE(DesksController::Get()->AreDesksBeingModified());
}
void OnDeskActivationChanged(const Desk* activated,
const Desk* deactivated) override {
EXPECT_TRUE(DesksController::Get()->AreDesksBeingModified());
}
void OnDeskSwitchAnimationFinished() override {
EXPECT_FALSE(DesksController::Get()->AreDesksBeingModified());
}
void OnDeskNameChanged(const Desk* desk,
const std::u16string& new_name) override {
++desk_name_changed_notify_counts_;
}
private:
std::vector<raw_ptr<const Desk, VectorExperimental>> desks_;
int desk_name_changed_notify_counts_ = 0;
};
class TestDeskObserver : public Desk::Observer {
public:
TestDeskObserver() = default;
TestDeskObserver(const TestDeskObserver&) = delete;
TestDeskObserver& operator=(const TestDeskObserver&) = delete;
~TestDeskObserver() override = default;
int notify_counts() const { return notify_counts_; }
void OnContentChanged() override { ++notify_counts_; }
void OnDeskDestroyed(const Desk* desk) override {}
void OnDeskNameChanged(const std::u16string& new_name) override {}
private:
int notify_counts_ = 0;
};
class FullScreenStateObserver : public ShellObserver {
public:
FullScreenStateObserver() { Shell::Get()->AddShellObserver(this); }
FullScreenStateObserver(const FullScreenStateObserver&) = delete;
FullScreenStateObserver& operator=(const FullScreenStateObserver&) = delete;
~FullScreenStateObserver() override {
Shell::Get()->RemoveShellObserver(this);
}
void OnFullscreenStateChanged(bool is_fullscreen,
aura::Window* container) override {
is_fullscreen_ = is_fullscreen;
}
bool is_fullscreen() const { return is_fullscreen_; }
private:
bool is_fullscreen_ = false;
};
struct DesksTestParams {
bool use_touch_gestures = false;
bool use_16_desks = false;
bool per_desk_shelf = false;
};
class DesksTest : public AshTestBase,
public ::testing::WithParamInterface<DesksTestParams> {
public:
enum class DeskBarScrollDirection { kLeft, kRight };
DesksTest() = default;
explicit DesksTest(base::test::TaskEnvironment::TimeSource time)
: AshTestBase(time) {}
DesksTest(const DesksTest&) = delete;
DesksTest& operator=(const DesksTest&) = delete;
~DesksTest() override = default;
void SetUp() override {
base::CommandLine::ForCurrentProcess()->AppendSwitch(
::switches::kUseFirstDisplayAsInternal);
scoped_feature_list_.InitWithFeatureStates(
{{features::kFeatureManagement16Desks, GetParam().use_16_desks},
{features::kPerDeskShelf, GetParam().per_desk_shelf}});
AshTestBase::SetUp();
SetVirtualKeyboardEnabled(true);
ash_test_helper()->saved_desk_test_helper()->WaitForDeskModels();
}
void TearDown() override {
AshTestBase::TearDown();
scoped_feature_list_.Reset();
}
void VerifyZeroStateNewDeskButtonVisibility(const DeskBarViewBase* bar_view,
bool expected_visibility) {
const auto state = bar_view->new_desk_button()->state();
EXPECT_TRUE(expected_visibility ? state == DeskIconButton::State::kZero
: state != DeskIconButton::State::kZero);
}
void VerifyExpandedStateNewDeskButtonVisibility(
const DeskBarViewBase* bar_view,
bool expected_visibility) {
const auto state = bar_view->new_desk_button()->state();
EXPECT_TRUE(expected_visibility
? state == DeskIconButton::State::kExpanded
: state != DeskIconButton::State::kExpanded);
}
void TryScrollOverviewDeskBar(DeskBarScrollDirection scroll_direction,
bool do_left_click = true) {
ScrollArrowButton* scroll_button = nullptr;
switch (scroll_direction) {
case DeskBarScrollDirection::kLeft:
scroll_button = DesksTestApi::GetDeskBarLeftScrollButton(
DeskBarViewBase::Type::kOverview);
break;
case DeskBarScrollDirection::kRight:
scroll_button = DesksTestApi::GetDeskBarRightScrollButton(
DeskBarViewBase::Type::kOverview);
break;
}
if (!scroll_button || !scroll_button->GetVisible()) {
return;
}
if (do_left_click) {
LeftClickOn(scroll_button);
} else {
GestureTapOn(scroll_button);
}
}
private:
base::test::ScopedFeatureList scoped_feature_list_;
};
TEST_P(DesksTest, DesksCreationAndRemoval) {
TestObserver observer;
auto* controller = DesksController::Get();
controller->AddObserver(&observer);
EXPECT_EQ(1u, controller->desks().size());
EXPECT_FALSE(controller->CanRemoveDesks());
EXPECT_TRUE(controller->CanCreateDesks());
while (controller->CanCreateDesks()) {
NewDesk();
}
EXPECT_EQ(desks_util::GetMaxNumberOfDesks(), controller->desks().size());
EXPECT_EQ(desks_util::GetMaxNumberOfDesks() - 1, observer.desks().size());
EXPECT_TRUE(controller->CanRemoveDesks());
while (controller->CanRemoveDesks()) {
RemoveDesk(observer.desks().back());
}
EXPECT_EQ(1u, controller->desks().size());
EXPECT_FALSE(controller->CanRemoveDesks());
EXPECT_TRUE(controller->CanCreateDesks());
EXPECT_TRUE(observer.desks().empty());
controller->RemoveObserver(&observer);
}
TEST_P(DesksTest, DeskRemovalLifetimeHistogram) {
base::HistogramTester histogram_tester;
auto* controller = DesksController::Get();
NewDesk();
auto* desk = controller->desks().back().get();
desk->set_creation_time(base::Time::Now() - base::Hours(8));
RemoveDesk(desk);
histogram_tester.ExpectBucketCount("Ash.Desks.DeskLifetime_2", 8, 1);
}
TEST_P(DesksTest, DeskRemovalWithPausedMruTracker) {
NewDesk();
auto* controller = DesksController::Get();
EXPECT_EQ(2u, controller->desks().size());
auto* desk_2 = controller->GetDeskAtIndex(1);
ActivateDesk(desk_2);
const auto win_bounds = gfx::Rect{10, 20, 250, 100};
auto win1 = CreateAppWindow(win_bounds);
auto* mru_tracker = Shell::Get()->mru_window_tracker();
mru_tracker->SetIgnoreActivations(true);
auto win2 = CreateAppWindow(win_bounds);
EnterOverview();
EXPECT_TRUE(OverviewController::Get()->InOverviewSession());
RemoveDesk(desk_2);
}
TEST_P(DesksTest, OnDeskNameChanged) {
TestObserver observer;
auto* controller = DesksController::Get();
controller->AddObserver(&observer);
NewDesk();
controller->GetDeskAtIndex(0)->SetName(u"test1", true);
controller->GetDeskAtIndex(1)->SetName(u"test2", true);
ASSERT_EQ(3, observer.desk_name_changed_notify_counts());
controller->RemoveObserver(&observer);
}
TEST_P(DesksTest, DesksTextfieldAddTooltipText) {
NewDesk();
auto* controller = DesksController::Get();
controller->GetDeskAtIndex(0)->SetName(u"test1", true);
std::u16string desk_name2(
u"test2 a very long desk name to test tooltip text");
controller->GetDeskAtIndex(1)->SetName(desk_name2, true);
EnterOverview();
EXPECT_TRUE(OverviewController::Get()->InOverviewSession());
auto* desks_bar_view =
GetOverviewGridForRoot(Shell::GetPrimaryRootWindow())->desks_bar_view();
auto* desk_name_view1 = desks_bar_view->mini_views()[0]->desk_name_view();
EXPECT_TRUE(desk_name_view1->GetRenderedTooltipText(gfx::Point()).empty());
auto* desk_name_view2 = desks_bar_view->mini_views()[1]->desk_name_view();
EXPECT_EQ(desk_name2, desk_name_view2->GetRenderedTooltipText(gfx::Point()));
}
TEST_P(DesksTest, DesksBarViewDeskCreation) {
auto* controller = DesksController::Get();
auto* overview_controller = OverviewController::Get();
EnterOverview();
EXPECT_TRUE(overview_controller->InOverviewSession());
const auto* overview_grid =
GetOverviewGridForRoot(Shell::GetPrimaryRootWindow());
const auto* desks_bar_view = overview_grid->desks_bar_view();
EXPECT_FALSE(overview_grid->IsDesksBarViewActive());
DCHECK(desks_bar_view);
EXPECT_TRUE(desks_bar_view->mini_views().empty());
auto* event_generator = GetEventGenerator();
LeftClickOn(desks_bar_view->default_desk_button());
RunScheduledLayoutForAllOverviewDeskBars();
EXPECT_FALSE(desks_bar_view->IsZeroState());
auto* new_desk_button = desks_bar_view->new_desk_button();
EXPECT_TRUE(new_desk_button->GetEnabled());
for (size_t i = 0; i < desks_util::GetMaxNumberOfDesks() + 2; ++i) {
LeftClickOn(new_desk_button);
RunScheduledLayoutForAllOverviewDeskBars();
TryScrollOverviewDeskBar(DeskBarScrollDirection::kRight);
RunScheduledLayoutForAllOverviewDeskBars();
}
EXPECT_TRUE(overview_grid->IsDesksBarViewActive());
EXPECT_EQ(desks_util::GetMaxNumberOfDesks(), controller->desks().size());
EXPECT_EQ(controller->desks().size(), desks_bar_view->mini_views().size());
EXPECT_FALSE(controller->CanCreateDesks());
EXPECT_TRUE(controller->CanRemoveDesks());
EXPECT_FALSE(new_desk_button->GetEnabled());
EXPECT_EQ(views::Button::STATE_DISABLED, new_desk_button->GetState());
auto* mini_view = desks_bar_view->mini_views().back().get();
EXPECT_FALSE(GetDeskActionVisibilityForMiniView(mini_view));
const gfx::Point mini_view_center =
mini_view->GetBoundsInScreen().CenterPoint();
event_generator->MoveMouseTo(mini_view_center);
RunScheduledLayoutForAllOverviewDeskBars();
EXPECT_TRUE(GetDeskActionVisibilityForMiniView(mini_view));
CloseDeskFromMiniView(mini_view, event_generator);
RunScheduledLayoutForAllOverviewDeskBars();
EXPECT_EQ(desks_util::GetMaxNumberOfDesks() - 1, controller->desks().size());
EXPECT_EQ(controller->desks().size(), desks_bar_view->mini_views().size());
EXPECT_TRUE(controller->CanCreateDesks());
EXPECT_TRUE(new_desk_button->GetEnabled());
EXPECT_EQ(views::Button::STATE_NORMAL, new_desk_button->GetState());
ExitOverview();
EXPECT_FALSE(overview_controller->InOverviewSession());
EnterOverview();
EXPECT_TRUE(overview_controller->InOverviewSession());
overview_grid =
overview_controller->overview_session()->GetGridWithRootWindow(
Shell::GetPrimaryRootWindow());
EXPECT_TRUE(overview_grid->IsDesksBarViewActive());
desks_bar_view = overview_grid->desks_bar_view();
DCHECK(desks_bar_view);
EXPECT_EQ(controller->desks().size(), desks_bar_view->mini_views().size());
EXPECT_TRUE(desks_bar_view->new_desk_button()->GetEnabled());
}
TEST_P(DesksTest, RemoveDeskWithEmptyName) {
auto* controller = DesksController::Get();
EnterOverview();
EXPECT_TRUE(OverviewController::Get()->InOverviewSession());
auto* overview_grid = GetOverviewGridForRoot(Shell::GetPrimaryRootWindow());
const auto* desks_bar_view = overview_grid->desks_bar_view();
auto* event_generator = GetEventGenerator();
controller->NewDesk(DesksCreationRemovalSource::kButton);
EXPECT_EQ(2u, controller->desks().size());
auto* mini_view = desks_bar_view->mini_views().back().get();
CloseDeskFromMiniView(mini_view, event_generator);
EXPECT_EQ(1u, controller->desks().size());
}
TEST_P(DesksTest, RemovingNonActiveDeskUpdatesWindowWorkspaces) {
auto* controller = DesksController::Get();
NewDesk();
NewDesk();
EXPECT_EQ(3u, controller->desks().size());
std::vector<std::unique_ptr<aura::Window>> windows;
for (int i = 0; i < 3; i++) {
windows.push_back(CreateAppWindow());
controller->SendToDeskAtIndex(windows[i].get(), i);
EXPECT_EQ(i, windows[i]->GetProperty(aura::client::kWindowWorkspaceKey));
}
ActivateDesk(controller->GetDeskAtIndex(2));
RemoveDesk(controller->GetDeskAtIndex(1));
EXPECT_EQ(2u, controller->desks().size());
EXPECT_EQ(0, windows[0]->GetProperty(aura::client::kWindowWorkspaceKey));
EXPECT_EQ(1, windows[1]->GetProperty(aura::client::kWindowWorkspaceKey));
EXPECT_EQ(1, windows[2]->GetProperty(aura::client::kWindowWorkspaceKey));
}
TEST_P(DesksTest, RemovingActiveDeskUpdatesWindowWorkspaces) {
auto* controller = DesksController::Get();
NewDesk();
NewDesk();
NewDesk();
EXPECT_EQ(4u, controller->desks().size());
std::vector<std::unique_ptr<aura::Window>> windows;
for (int i = 0; i < 4; i++) {
windows.push_back(CreateAppWindow());
controller->SendToDeskAtIndex(windows[i].get(), i);
EXPECT_EQ(i, windows[i]->GetProperty(aura::client::kWindowWorkspaceKey));
}
const Desk* desk_2 = controller->GetDeskAtIndex(1);
ActivateDesk(desk_2);
RemoveDesk(desk_2);
EXPECT_EQ(3u, controller->desks().size());
EXPECT_EQ(controller->GetDeskAtIndex(0), controller->active_desk());
EXPECT_EQ(0, windows[0]->GetProperty(aura::client::kWindowWorkspaceKey));
EXPECT_EQ(0, windows[1]->GetProperty(aura::client::kWindowWorkspaceKey));
EXPECT_EQ(1, windows[2]->GetProperty(aura::client::kWindowWorkspaceKey));
EXPECT_EQ(2, windows[3]->GetProperty(aura::client::kWindowWorkspaceKey));
}
TEST_P(DesksTest, GestureTapOnNewDeskButton) {
EnterOverview();
EXPECT_TRUE(OverviewController::Get()->InOverviewSession());
const auto* overview_grid =
GetOverviewGridForRoot(Shell::GetPrimaryRootWindow());
const auto* desks_bar_view = overview_grid->desks_bar_view();
ASSERT_TRUE(desks_bar_view);
LeftClickOn(desks_bar_view->default_desk_button());
auto* new_desk_button = desks_bar_view->new_desk_button();
EXPECT_TRUE(new_desk_button->GetEnabled());
for (size_t i = 0; i < desks_util::GetMaxNumberOfDesks() + 2; ++i) {
GestureTapOn(new_desk_button);
RunScheduledLayoutForAllOverviewDeskBars();
TryScrollOverviewDeskBar(DeskBarScrollDirection::kRight,
false);
}
EXPECT_FALSE(new_desk_button->GetEnabled());
EXPECT_EQ(views::Button::STATE_DISABLED, new_desk_button->GetState());
}
TEST_P(DesksTest, DeskActivation) {
auto* controller = DesksController::Get();
ASSERT_EQ(1u, controller->desks().size());
const Desk* desk_1 = controller->GetDeskAtIndex(0);
EXPECT_EQ(desk_1, controller->active_desk());
EXPECT_TRUE(desk_1->is_active());
auto* root = Shell::GetPrimaryRootWindow();
EXPECT_TRUE(desk_1->GetDeskContainerForRoot(root)->IsVisible());
EXPECT_EQ(desks_util::GetActiveDeskContainerForRoot(root),
desk_1->GetDeskContainerForRoot(root));
NewDesk();
NewDesk();
NewDesk();
ASSERT_EQ(4u, controller->desks().size());
const Desk* desk_2 = controller->GetDeskAtIndex(1);
const Desk* desk_3 = controller->GetDeskAtIndex(2);
const Desk* desk_4 = controller->GetDeskAtIndex(3);
EXPECT_FALSE(controller->AreDesksBeingModified());
ActivateDesk(desk_2);
EXPECT_FALSE(controller->AreDesksBeingModified());
EXPECT_EQ(desk_2, controller->active_desk());
EXPECT_FALSE(desk_1->is_active());
EXPECT_TRUE(desk_2->is_active());
EXPECT_FALSE(desk_3->is_active());
EXPECT_FALSE(desk_4->is_active());
EXPECT_FALSE(desk_1->GetDeskContainerForRoot(root)->IsVisible());
EXPECT_TRUE(desk_2->GetDeskContainerForRoot(root)->IsVisible());
EXPECT_FALSE(desk_3->GetDeskContainerForRoot(root)->IsVisible());
EXPECT_FALSE(desk_4->GetDeskContainerForRoot(root)->IsVisible());
EXPECT_FALSE(controller->AreDesksBeingModified());
RemoveDesk(desk_2);
EXPECT_FALSE(controller->AreDesksBeingModified());
ASSERT_EQ(3u, controller->desks().size());
EXPECT_EQ(desk_1, controller->active_desk());
EXPECT_TRUE(desk_1->is_active());
EXPECT_FALSE(desk_3->is_active());
EXPECT_FALSE(desk_4->is_active());
EXPECT_TRUE(desk_1->GetDeskContainerForRoot(root)->IsVisible());
EXPECT_FALSE(desk_3->GetDeskContainerForRoot(root)->IsVisible());
EXPECT_FALSE(desk_4->GetDeskContainerForRoot(root)->IsVisible());
EXPECT_FALSE(controller->AreDesksBeingModified());
RemoveDesk(desk_1);
EXPECT_FALSE(controller->AreDesksBeingModified());
ASSERT_EQ(2u, controller->desks().size());
EXPECT_EQ(desk_3, controller->active_desk());
EXPECT_TRUE(desk_3->is_active());
EXPECT_FALSE(desk_4->is_active());
EXPECT_TRUE(desk_3->GetDeskContainerForRoot(root)->IsVisible());
EXPECT_FALSE(desk_4->GetDeskContainerForRoot(root)->IsVisible());
}
TEST_P(DesksTest, TestWindowPositioningPaused) {
auto* controller = DesksController::Get();
NewDesk();
const auto win0_bounds = gfx::Rect{10, 20, 250, 100};
const auto win1_bounds = gfx::Rect{50, 50, 200, 200};
auto win0 = CreateAppWindow(win0_bounds);
auto win1 = CreateAppWindow(win1_bounds);
WindowState* window_state = WindowState::Get(win0.get());
window_state->SetWindowPositionManaged(true);
window_state = WindowState::Get(win1.get());
window_state->SetWindowPositionManaged(true);
EXPECT_EQ(win0_bounds, win0->GetBoundsInScreen());
EXPECT_EQ(win1_bounds, win1->GetBoundsInScreen());
Desk* desk_2 = controller->GetDeskAtIndex(1);
controller->MoveWindowFromActiveDeskTo(
win1.get(), desk_2, win1->GetRootWindow(),
DesksMoveWindowFromActiveDeskSource::kDragAndDrop);
EXPECT_EQ(win0_bounds, win0->GetBoundsInScreen());
EXPECT_EQ(win1_bounds, win1->GetBoundsInScreen());
RemoveDesk(desk_2);
EXPECT_EQ(win0_bounds, win0->GetBoundsInScreen());
EXPECT_EQ(win1_bounds, win1->GetBoundsInScreen());
}
TEST_P(DesksTest, DeskActivationDualDisplay) {
UpdateDisplay("700x600,400x500");
auto* controller = DesksController::Get();
ASSERT_EQ(1u, controller->desks().size());
const Desk* desk_1 = controller->GetDeskAtIndex(0);
EXPECT_EQ(desk_1, controller->active_desk());
EXPECT_TRUE(desk_1->is_active());
NewDesk();
NewDesk();
NewDesk();
ASSERT_EQ(4u, controller->desks().size());
const Desk* desk_2 = controller->GetDeskAtIndex(1);
const Desk* desk_3 = controller->GetDeskAtIndex(2);
const Desk* desk_4 = controller->GetDeskAtIndex(3);
EXPECT_FALSE(controller->AreDesksBeingModified());
ActivateDesk(desk_2);
EXPECT_FALSE(controller->AreDesksBeingModified());
EXPECT_EQ(desk_2, controller->active_desk());
EXPECT_FALSE(desk_1->is_active());
EXPECT_TRUE(desk_2->is_active());
EXPECT_FALSE(desk_3->is_active());
EXPECT_FALSE(desk_4->is_active());
auto roots = Shell::GetAllRootWindows();
ASSERT_EQ(2u, roots.size());
EXPECT_FALSE(desk_1->GetDeskContainerForRoot(roots[0])->IsVisible());
EXPECT_FALSE(desk_1->GetDeskContainerForRoot(roots[1])->IsVisible());
EXPECT_TRUE(desk_2->GetDeskContainerForRoot(roots[0])->IsVisible());
EXPECT_TRUE(desk_2->GetDeskContainerForRoot(roots[1])->IsVisible());
EXPECT_FALSE(desk_3->GetDeskContainerForRoot(roots[0])->IsVisible());
EXPECT_FALSE(desk_3->GetDeskContainerForRoot(roots[1])->IsVisible());
EXPECT_FALSE(desk_4->GetDeskContainerForRoot(roots[0])->IsVisible());
EXPECT_FALSE(desk_4->GetDeskContainerForRoot(roots[1])->IsVisible());
}
TEST_P(DesksTest, TransientWindows) {
auto* controller = DesksController::Get();
ASSERT_EQ(1u, controller->desks().size());
const Desk* desk_1 = controller->GetDeskAtIndex(0);
EXPECT_EQ(desk_1, controller->active_desk());
EXPECT_TRUE(desk_1->is_active());
auto win0 = CreateAppWindow(gfx::Rect(0, 0, 250, 100));
auto win1 = CreateTransientWindow(win0.get(), gfx::Rect(100, 100, 100, 100));
EXPECT_EQ(2u, desk_1->windows().size());
EXPECT_TRUE(DoesActiveDeskContainWindow(win0.get()));
EXPECT_TRUE(DoesActiveDeskContainWindow(win1.get()));
auto* root = Shell::GetPrimaryRootWindow();
EXPECT_EQ(desks_util::GetActiveDeskContainerForRoot(root),
desks_util::GetDeskContainerForContext(win0.get()));
EXPECT_EQ(desks_util::GetActiveDeskContainerForRoot(root),
desks_util::GetDeskContainerForContext(win1.get()));
NewDesk();
const Desk* desk_2 = controller->GetDeskAtIndex(1);
EXPECT_TRUE(desk_2->windows().empty());
ActivateDesk(desk_2);
EXPECT_FALSE(desk_1->is_active());
EXPECT_TRUE(desk_2->is_active());
auto win2 = CreateTransientWindow(win1.get(), gfx::Rect(100, 100, 50, 50));
EXPECT_FALSE(controller->AreDesksBeingModified());
EXPECT_EQ(3u, desk_1->windows().size());
EXPECT_TRUE(desk_2->windows().empty());
EXPECT_FALSE(DoesActiveDeskContainWindow(win2.get()));
auto* desk_1_container = desk_1->GetDeskContainerForRoot(root);
EXPECT_EQ(win0.get(), desk_1_container->children()[0]);
EXPECT_EQ(win1.get(), desk_1_container->children()[1]);
EXPECT_EQ(win2.get(), desk_1_container->children()[2]);
RemoveDesk(desk_1);
EXPECT_EQ(1u, controller->desks().size());
EXPECT_EQ(desk_2, controller->active_desk());
EXPECT_EQ(3u, desk_2->windows().size());
auto* desk_2_container = desk_2->GetDeskContainerForRoot(root);
EXPECT_EQ(win0.get(), desk_2_container->children()[0]);
EXPECT_EQ(win1.get(), desk_2_container->children()[1]);
EXPECT_EQ(win2.get(), desk_2_container->children()[2]);
}
TEST_P(DesksTest, WindowStackingAfterWindowMoveToAnotherDesk) {
auto* controller = DesksController::Get();
auto win0 = CreateAppWindow(gfx::Rect(0, 0, 250, 100));
NewDesk();
Desk* desk_2 = controller->GetDeskAtIndex(1);
ActivateDesk(desk_2);
auto win1 = CreateAppWindow(gfx::Rect(10, 10, 250, 100));
auto win2 = CreateTransientWindow(win1.get(), gfx::Rect(100, 100, 100, 100));
wm::ActivateWindow(win2.get());
auto win3 = CreateAppWindow(gfx::Rect(20, 20, 250, 100));
Desk* desk_1 = controller->GetDeskAtIndex(0);
ActivateDesk(desk_1);
EXPECT_EQ(win0.get(), window_util::GetActiveWindow());
auto* mru_tracker = Shell::Get()->mru_window_tracker();
EXPECT_EQ(mru_tracker->BuildMruWindowList(DesksMruType::kAllDesks),
aura::WindowTracker::WindowList({
win0.get(),
win3.get(),
win2.get(),
win1.get(),
}));
ActivateDesk(desk_2);
EXPECT_EQ(mru_tracker->BuildMruWindowList(DesksMruType::kAllDesks),
aura::WindowTracker::WindowList({
win3.get(),
win0.get(),
win2.get(),
win1.get(),
}));
desk_2->MoveWindowToDesk(win2.get(), desk_1, win1->GetRootWindow(),
true);
desk_2->MoveWindowToDesk(win3.get(), desk_1, win1->GetRootWindow(),
true);
EXPECT_TRUE(window_util::IsStackedBelow(win1.get(), win2.get()));
EXPECT_TRUE(window_util::IsStackedBelow(win2.get(), win0.get()));
EXPECT_TRUE(window_util::IsStackedBelow(win0.get(), win3.get()));
}
TEST_P(DesksTest, TransientModalChildren) {
auto* controller = DesksController::Get();
NewDesk();
NewDesk();
ASSERT_EQ(3u, controller->desks().size());
Desk* desk_1 = controller->GetDeskAtIndex(0);
Desk* desk_2 = controller->GetDeskAtIndex(1);
Desk* desk_3 = controller->GetDeskAtIndex(2);
EXPECT_EQ(desk_1, controller->active_desk());
EXPECT_TRUE(desk_1->is_active());
auto win0 = CreateAppWindow(gfx::Rect(0, 0, 250, 100));
auto win1 = CreateTransientModalChildWindow(win0.get());
EXPECT_EQ(win1.get(), ::wm::GetModalTransient(win0.get()));
auto win2 = CreateAppWindow(gfx::Rect(0, 0, 200, 100));
ASSERT_EQ(3u, desk_1->windows().size());
auto* root = Shell::GetPrimaryRootWindow();
auto* desk_1_container = desk_1->GetDeskContainerForRoot(root);
EXPECT_EQ(win0.get(), desk_1_container->children()[0]);
EXPECT_EQ(win1.get(), desk_1_container->children()[1]);
EXPECT_EQ(win2.get(), desk_1_container->children()[2]);
RemoveDesk(desk_1);
EXPECT_EQ(desk_2, controller->active_desk());
ASSERT_EQ(3u, desk_2->windows().size());
auto* desk_2_container = desk_2->GetDeskContainerForRoot(root);
EXPECT_EQ(win0.get(), desk_2_container->children()[0]);
EXPECT_EQ(win1.get(), desk_2_container->children()[1]);
EXPECT_EQ(win2.get(), desk_2_container->children()[2]);
EXPECT_EQ(win1.get(), ::wm::GetModalTransient(win0.get()));
controller->MoveWindowFromActiveDeskTo(
win1.get(), desk_3, win1->GetRootWindow(),
DesksMoveWindowFromActiveDeskSource::kDragAndDrop);
ASSERT_EQ(1u, desk_2->windows().size());
ASSERT_EQ(2u, desk_3->windows().size());
EXPECT_EQ(win2.get(), desk_2_container->children()[0]);
auto* desk_3_container = desk_3->GetDeskContainerForRoot(root);
EXPECT_EQ(win0.get(), desk_3_container->children()[0]);
EXPECT_EQ(win1.get(), desk_3_container->children()[1]);
ActivateDesk(desk_3);
EXPECT_EQ(win1.get(), ::wm::GetModalTransient(win0.get()));
}
TEST_P(DesksTest, WindowActivation) {
auto win0 = CreateAppWindow(gfx::Rect(0, 0, 250, 100));
auto win1 = CreateAppWindow(gfx::Rect(50, 50, 200, 200));
auto win2 = CreateAppWindow(gfx::Rect(100, 100, 100, 100));
EXPECT_TRUE(DoesActiveDeskContainWindow(win0.get()));
EXPECT_TRUE(DoesActiveDeskContainWindow(win1.get()));
EXPECT_TRUE(DoesActiveDeskContainWindow(win2.get()));
wm::ActivateWindow(win0.get());
auto* controller = DesksController::Get();
NewDesk();
ASSERT_EQ(2u, controller->desks().size());
Desk* desk_1 = controller->GetDeskAtIndex(0);
const Desk* desk_2 = controller->GetDeskAtIndex(1);
EXPECT_EQ(desk_1, controller->active_desk());
EXPECT_EQ(3u, desk_1->windows().size());
EXPECT_TRUE(desk_2->windows().empty());
EXPECT_EQ(win0.get(), window_util::GetActiveWindow());
ActivateDesk(desk_2);
EXPECT_EQ(desk_2, controller->active_desk());
EXPECT_EQ(3u, desk_1->windows().size());
EXPECT_TRUE(desk_2->windows().empty());
EXPECT_EQ(nullptr, window_util::GetActiveWindow());
EXPECT_TRUE(wm::CanActivateWindow(win0.get()));
EXPECT_TRUE(wm::CanActivateWindow(win1.get()));
EXPECT_TRUE(wm::CanActivateWindow(win2.get()));
auto win3 = CreateAppWindow(gfx::Rect(0, 0, 300, 200));
auto win4 = CreateAppWindow(gfx::Rect(10, 30, 400, 200));
wm::ActivateWindow(win3.get());
EXPECT_EQ(2u, desk_2->windows().size());
EXPECT_TRUE(DoesActiveDeskContainWindow(win3.get()));
EXPECT_TRUE(DoesActiveDeskContainWindow(win4.get()));
EXPECT_FALSE(DoesActiveDeskContainWindow(win0.get()));
EXPECT_FALSE(DoesActiveDeskContainWindow(win1.get()));
EXPECT_FALSE(DoesActiveDeskContainWindow(win2.get()));
EXPECT_EQ(win3.get(), window_util::GetActiveWindow());
win0.reset();
EXPECT_EQ(2u, desk_1->windows().size());
EXPECT_EQ(2u, desk_2->windows().size());
EXPECT_EQ(win3.get(), window_util::GetActiveWindow());
ActivateDesk(desk_1);
EXPECT_EQ(desk_1, controller->active_desk());
EXPECT_TRUE(wm::CanActivateWindow(win1.get()));
EXPECT_TRUE(wm::CanActivateWindow(win2.get()));
EXPECT_TRUE(wm::CanActivateWindow(win3.get()));
EXPECT_TRUE(wm::CanActivateWindow(win4.get()));
EXPECT_EQ(win2.get(), window_util::GetActiveWindow());
TestDeskObserver observer;
desk_1->AddObserver(&observer);
RemoveDesk(desk_2);
EXPECT_EQ(1u, controller->desks().size());
EXPECT_EQ(desk_1, controller->active_desk());
EXPECT_EQ(4u, desk_1->windows().size());
EXPECT_EQ(1, observer.notify_counts());
desk_1->RemoveObserver(&observer);
EXPECT_TRUE(DoesActiveDeskContainWindow(win3.get()));
EXPECT_TRUE(DoesActiveDeskContainWindow(win4.get()));
EXPECT_EQ(win2.get(), window_util::GetActiveWindow());
EXPECT_TRUE(wm::CanActivateWindow(win3.get()));
EXPECT_TRUE(wm::CanActivateWindow(win4.get()));
}
TEST_P(DesksTest, ActivateDeskFromOverview) {
auto* controller = DesksController::Get();
auto* overview_controller = OverviewController::Get();
auto* event_generator = GetEventGenerator();
NewDesk();
NewDesk();
NewDesk();
ASSERT_EQ(4u, controller->desks().size());
auto win0 = CreateAppWindow(gfx::Rect(0, 0, 250, 100));
auto win1 = CreateAppWindow(gfx::Rect(50, 50, 200, 200));
wm::ActivateWindow(win1.get());
EXPECT_EQ(win1.get(), window_util::GetActiveWindow());
{
EnterOverview();
EXPECT_TRUE(overview_controller->InOverviewSession());
const auto* overview_grid =
GetOverviewGridForRoot(Shell::GetPrimaryRootWindow());
const auto* desks_bar_view = overview_grid->desks_bar_view();
ASSERT_TRUE(desks_bar_view);
ASSERT_EQ(4u, desks_bar_view->mini_views().size());
EXPECT_EQ(2u, overview_grid->item_list().size());
const Desk* desk_4 = controller->GetDeskAtIndex(3);
EXPECT_EQ(0, controller->GetActiveDeskIndex());
auto* mini_view = desks_bar_view->mini_views().back().get();
EXPECT_EQ(desk_4, mini_view->desk());
EXPECT_FALSE(GetDeskActionVisibilityForMiniView(mini_view));
DeskSwitchAnimationWaiter waiter;
LeftClickOn(mini_view);
waiter.Wait();
EXPECT_EQ(3, controller->GetActiveDeskIndex());
EXPECT_FALSE(overview_controller->InOverviewSession());
base::RunLoop().RunUntilIdle();
EXPECT_EQ(nullptr, window_util::GetActiveWindow());
auto win2 = CreateAppWindow(gfx::Rect(50, 50, 200, 200));
wm::ActivateWindow(win2.get());
EnterOverview();
EXPECT_TRUE(overview_controller->InOverviewSession());
overview_grid = GetOverviewGridForRoot(Shell::GetPrimaryRootWindow());
EXPECT_EQ(1u, overview_grid->item_list().size());
ExitOverview();
EXPECT_FALSE(overview_controller->InOverviewSession());
base::RunLoop().RunUntilIdle();
EXPECT_EQ(win2.get(), window_util::GetActiveWindow());
}
{
EnterOverview();
const auto* overview_grid =
GetOverviewGridForRoot(Shell::GetPrimaryRootWindow());
DeskSwitchAnimationWaiter waiter;
DoubleClickOnView(overview_grid->desks_bar_view()->mini_views().front(),
event_generator);
waiter.Wait();
EXPECT_EQ(0, controller->GetActiveDeskIndex());
EXPECT_FALSE(overview_controller->InOverviewSession());
}
{
EnterOverview();
const auto* overview_grid =
GetOverviewGridForRoot(Shell::GetPrimaryRootWindow());
DeskSwitchAnimationWaiter waiter;
SendAccessibleActionToView(
overview_grid->desks_bar_view()->mini_views()[1]->desk_preview(),
ax::mojom::Action::kDoDefault);
waiter.Wait();
EXPECT_EQ(1, controller->GetActiveDeskIndex());
EXPECT_FALSE(overview_controller->InOverviewSession());
}
}
TEST_P(DesksTest, ActivateDeskFromOverviewDualDisplay) {
UpdateDisplay("700x600,400x500");
auto* controller = DesksController::Get();
NewDesk();
NewDesk();
NewDesk();
ASSERT_EQ(4u, controller->desks().size());
auto* overview_controller = OverviewController::Get();
EnterOverview();
EXPECT_TRUE(overview_controller->InOverviewSession());
auto roots = Shell::GetAllRootWindows();
ASSERT_EQ(2u, roots.size());
const auto* overview_grid = GetOverviewGridForRoot(roots[1]);
const auto* desks_bar_view = overview_grid->desks_bar_view();
ASSERT_TRUE(desks_bar_view);
ASSERT_EQ(4u, desks_bar_view->mini_views().size());
const Desk* desk_4 = controller->GetDeskAtIndex(3);
EXPECT_FALSE(desk_4->is_active());
const auto* mini_view = desks_bar_view->mini_views().back().get();
const gfx::Point mini_view_center =
mini_view->GetBoundsInScreen().CenterPoint();
auto* event_generator = GetEventGenerator();
event_generator->MoveMouseTo(mini_view_center);
DeskSwitchAnimationWaiter waiter;
event_generator->ClickLeftButton();
waiter.Wait();
EXPECT_TRUE(desk_4->is_active());
EXPECT_FALSE(overview_controller->InOverviewSession());
}
TEST_P(DesksTest, RemoveInactiveDeskFromOverview) {
auto* controller = DesksController::Get();
NewDesk();
NewDesk();
NewDesk();
ASSERT_EQ(4u, controller->desks().size());
auto win0 = CreateAppWindow(gfx::Rect(0, 0, 250, 100));
auto win1 = CreateAppWindow(gfx::Rect(50, 50, 200, 200));
auto win2 = CreateAppWindow(gfx::Rect(50, 50, 200, 200));
wm::ActivateWindow(win0.get());
EXPECT_EQ(win0.get(), window_util::GetActiveWindow());
auto* mru_tracker = Shell::Get()->mru_window_tracker();
EXPECT_THAT(mru_tracker->BuildMruWindowList(DesksMruType::kActiveDesk),
ElementsAre(win0.get(), win2.get(), win1.get()));
Desk* desk_4 = controller->GetDeskAtIndex(3);
ActivateDesk(desk_4);
auto* overview_controller = OverviewController::Get();
auto win3 = CreateAppWindow(gfx::Rect(50, 50, 200, 200));
EnterOverview();
EXPECT_TRUE(overview_controller->InOverviewSession());
const auto* overview_grid =
GetOverviewGridForRoot(Shell::GetPrimaryRootWindow());
EXPECT_EQ(1u, overview_grid->item_list().size());
const auto* desks_bar_view = overview_grid->desks_bar_view();
ASSERT_TRUE(desks_bar_view);
ASSERT_EQ(4u, desks_bar_view->mini_views().size());
Desk* desk_1 = controller->GetDeskAtIndex(0);
auto* mini_view = desks_bar_view->mini_views().front().get();
EXPECT_EQ(desk_1, mini_view->desk());
TestDeskObserver desk_4_observer;
desk_4->AddObserver(&desk_4_observer);
TestDeskObserver desk_1_observer;
desk_1->AddObserver(&desk_1_observer);
views::MenuItemView* menu_item =
DesksTestApi::OpenDeskContextMenuAndGetMenuItem(
Shell::GetPrimaryRootWindow(), DeskBarViewBase::Type::kOverview,
0u, DeskActionContextMenu::CommandId::kCombineDesks);
LeftClickOn(menu_item);
EXPECT_EQ(0, desk_1_observer.notify_counts());
EXPECT_EQ(1, desk_4_observer.notify_counts());
ASSERT_EQ(3u, desks_bar_view->mini_views().size());
EXPECT_TRUE(overview_controller->InOverviewSession());
ASSERT_EQ(4u, overview_grid->item_list().size());
EXPECT_TRUE(overview_grid->GetOverviewItemContaining(win0.get()));
EXPECT_TRUE(overview_grid->GetOverviewItemContaining(win1.get()));
EXPECT_TRUE(overview_grid->GetOverviewItemContaining(win2.get()));
EXPECT_TRUE(overview_grid->GetOverviewItemContaining(win3.get()));
EXPECT_EQ(overview_grid->GetOverviewItemContaining(win3.get()),
overview_grid->item_list()[0].get());
EXPECT_EQ(overview_grid->GetOverviewItemContaining(win0.get()),
overview_grid->item_list()[1].get());
EXPECT_EQ(overview_grid->GetOverviewItemContaining(win2.get()),
overview_grid->item_list()[2].get());
EXPECT_EQ(overview_grid->GetOverviewItemContaining(win1.get()),
overview_grid->item_list()[3].get());
base::RunLoop().RunUntilIdle();
EXPECT_TRUE(overview_controller->InOverviewSession());
mini_view = desks_bar_view->mini_views().front();
EXPECT_TRUE(mini_view->desk()->windows().empty());
CloseDeskFromMiniView(mini_view, GetEventGenerator());
EXPECT_EQ(1, desk_4_observer.notify_counts());
ExitOverview();
EXPECT_FALSE(overview_controller->InOverviewSession());
EXPECT_EQ(1, desk_4_observer.notify_counts());
desk_4->RemoveObserver(&desk_4_observer);
EXPECT_THAT(mru_tracker->BuildMruWindowList(DesksMruType::kActiveDesk),
ElementsAre(win3.get(), win0.get(), win2.get(), win1.get()));
EXPECT_THAT(desk_4->GetDeskContainerForRoot(Shell::GetPrimaryRootWindow())
->children(),
ElementsAre(win1.get(), win2.get(), win0.get(), win3.get()));
}
TEST_P(DesksTest, RemoveActiveDeskFromOverview) {
auto* controller = DesksController::Get();
NewDesk();
ASSERT_EQ(2u, controller->desks().size());
Desk* desk_1 = controller->GetDeskAtIndex(0);
auto win0 = CreateAppWindow(gfx::Rect(0, 0, 250, 100));
auto win1 = CreateAppWindow(gfx::Rect(50, 50, 200, 200));
wm::ActivateWindow(win0.get());
EXPECT_EQ(win0.get(), window_util::GetActiveWindow());
Desk* desk_2 = controller->GetDeskAtIndex(1);
ActivateDesk(desk_2);
auto win2 = CreateAppWindow(gfx::Rect(50, 50, 200, 200));
auto win3 = CreateAppWindow(gfx::Rect(50, 50, 200, 200));
wm::ActivateWindow(win2.get());
EXPECT_EQ(win2.get(), window_util::GetActiveWindow());
auto* mru_tracker = Shell::Get()->mru_window_tracker();
EXPECT_THAT(mru_tracker->BuildMruWindowList(DesksMruType::kAllDesks),
ElementsAre(win2.get(), win3.get(), win0.get(), win1.get()));
auto* overview_controller = OverviewController::Get();
EnterOverview();
EXPECT_TRUE(overview_controller->InOverviewSession());
const auto* overview_grid =
GetOverviewGridForRoot(Shell::GetPrimaryRootWindow());
EXPECT_EQ(2u, overview_grid->item_list().size());
const auto* desks_bar_view = overview_grid->desks_bar_view();
ASSERT_TRUE(desks_bar_view);
ASSERT_EQ(2u, desks_bar_view->mini_views().size());
auto* mini_view = desks_bar_view->mini_views().back().get();
EXPECT_EQ(desk_2, mini_view->desk());
TestDeskObserver desk_1_observer;
desk_1->AddObserver(&desk_1_observer);
TestDeskObserver desk_2_observer;
desk_2->AddObserver(&desk_2_observer);
views::MenuItemView* menu_item =
DesksTestApi::OpenDeskContextMenuAndGetMenuItem(
Shell::GetPrimaryRootWindow(), DeskBarViewBase::Type::kOverview,
1u, DeskActionContextMenu::CommandId::kCombineDesks);
LeftClickOn(menu_item);
EXPECT_EQ(1, desk_1_observer.notify_counts());
EXPECT_EQ(0, desk_2_observer.notify_counts());
EXPECT_TRUE(desks_bar_view->GetWidget()->IsVisible());
EXPECT_TRUE(DoesActiveDeskContainWindow(
desks_bar_view->GetWidget()->GetNativeWindow()));
ASSERT_EQ(1u, controller->desks().size());
ASSERT_EQ(1u, desks_bar_view->mini_views().size());
EXPECT_TRUE(desk_1->is_active());
EXPECT_TRUE(overview_controller->InOverviewSession());
EXPECT_EQ(4u, overview_grid->item_list().size());
EXPECT_TRUE(overview_grid->GetOverviewItemContaining(win0.get()));
EXPECT_TRUE(overview_grid->GetOverviewItemContaining(win1.get()));
EXPECT_TRUE(overview_grid->GetOverviewItemContaining(win2.get()));
EXPECT_TRUE(overview_grid->GetOverviewItemContaining(win3.get()));
EXPECT_THAT(mru_tracker->BuildMruWindowList(DesksMruType::kActiveDesk),
ElementsAre(win0.get(), win1.get(), win2.get(), win3.get()));
EXPECT_EQ(overview_grid->GetOverviewItemContaining(win0.get()),
overview_grid->item_list()[0].get());
EXPECT_EQ(overview_grid->GetOverviewItemContaining(win1.get()),
overview_grid->item_list()[1].get());
EXPECT_EQ(overview_grid->GetOverviewItemContaining(win2.get()),
overview_grid->item_list()[2].get());
EXPECT_EQ(overview_grid->GetOverviewItemContaining(win3.get()),
overview_grid->item_list()[3].get());
base::RunLoop().RunUntilIdle();
EXPECT_TRUE(overview_controller->InOverviewSession());
ExitOverview();
EXPECT_FALSE(overview_controller->InOverviewSession());
EXPECT_EQ(1, desk_1_observer.notify_counts());
desk_1->RemoveObserver(&desk_1_observer);
}
TEST_P(DesksTest,
RemoveActiveDeskWithAllDeskWindowFromOverviewWithNewDeskOfEmptyName) {
auto* controller = DesksController::Get();
NewDesk();
auto win1 = CreateAppWindow();
views::Widget::GetWidgetForNativeWindow(win1.get())
->SetVisibleOnAllWorkspaces(true);
ASSERT_TRUE(desks_util::IsWindowVisibleOnAllWorkspaces(win1.get()));
EnterOverview();
LeftClickOn(GetPrimaryRootDesksBarView()->new_desk_button());
ASSERT_EQ(3u, controller->desks().size());
Desk* desk_1 = controller->GetDeskAtIndex(0);
Desk* desk_2 = controller->GetDeskAtIndex(1);
Desk* desk_3 = controller->GetDeskAtIndex(2);
ASSERT_TRUE(desk_1->is_active());
controller->RemoveDesk(desk_1, DesksCreationRemovalSource::kButton,
DeskCloseType::kCloseAllWindowsAndWait);
ASSERT_EQ(desk_2, controller->GetTargetActiveDesk());
EXPECT_TRUE(OverviewController::Get()->InOverviewSession());
controller->RemoveDesk(desk_2, DesksCreationRemovalSource::kButton,
DeskCloseType::kCloseAllWindowsAndWait);
ASSERT_EQ(desk_3, controller->GetTargetActiveDesk());
EXPECT_TRUE(OverviewController::Get()->InOverviewSession());
EXPECT_EQ(1u, GetPrimaryRootDesksBarView()->mini_views().size());
}
TEST_P(DesksTest, ActivateActiveDeskFromOverview) {
auto* controller = DesksController::Get();
NewDesk();
ASSERT_EQ(2u, controller->desks().size());
auto* overview_controller = OverviewController::Get();
EnterOverview();
EXPECT_TRUE(overview_controller->InOverviewSession());
const auto* overview_grid =
GetOverviewGridForRoot(Shell::GetPrimaryRootWindow());
const auto* desks_bar_view = overview_grid->desks_bar_view();
const Desk* desk_1 = controller->GetDeskAtIndex(0);
const auto* mini_view = desks_bar_view->mini_views().front().get();
LeftClickOn(mini_view);
EXPECT_FALSE(overview_controller->InOverviewSession());
EXPECT_TRUE(desk_1->is_active());
EXPECT_EQ(desk_1, controller->active_desk());
}
TEST_P(DesksTest, MinimizedWindow) {
auto* controller = DesksController::Get();
NewDesk();
ASSERT_EQ(2u, controller->desks().size());
const Desk* desk_1 = controller->GetDeskAtIndex(0);
const Desk* desk_2 = controller->GetDeskAtIndex(1);
auto win0 = CreateAppWindow(gfx::Rect(0, 0, 250, 100));
wm::ActivateWindow(win0.get());
EXPECT_EQ(win0.get(), window_util::GetActiveWindow());
auto* window_state = WindowState::Get(win0.get());
window_state->Minimize();
EXPECT_TRUE(window_state->IsMinimized());
EXPECT_EQ(1u, Shell::Get()
->mru_window_tracker()
->BuildMruWindowList(kActiveDesk)
.size());
ActivateDesk(desk_2);
EXPECT_TRUE(Shell::Get()
->mru_window_tracker()
->BuildMruWindowList(kActiveDesk)
.empty());
ActivateDesk(desk_1);
EXPECT_TRUE(window_state->IsMinimized());
EXPECT_NE(win0.get(), window_util::GetActiveWindow());
}
TEST_P(DesksTest, AppListStaysOpenInClamshell) {
auto* controller = DesksController::Get();
NewDesk();
ASSERT_EQ(2u, controller->desks().size());
auto win0 = CreateAppWindow(gfx::Rect(400, 400));
ActivateDesk(controller->GetDeskAtIndex(1));
auto win1 = CreateAppWindow(gfx::Rect(400, 400));
auto* app_list_controller = Shell::Get()->app_list_controller();
app_list_controller->ShowAppList(AppListShowSource::kSearchKey);
ASSERT_TRUE(app_list_controller->IsVisible());
ActivateDesk(controller->GetDeskAtIndex(0));
EXPECT_TRUE(app_list_controller->IsVisible());
}
TEST_P(DesksTest, AppListActivationInTablet) {
auto* controller = DesksController::Get();
NewDesk();
ASSERT_EQ(2u, controller->desks().size());
auto window = CreateAppWindow(gfx::Rect(400, 400));
ASSERT_EQ(window.get(), window_util::GetActiveWindow());
TabletModeControllerTestApi().EnterTabletMode();
ActivateDesk(controller->GetDeskAtIndex(1));
auto* app_list_controller = Shell::Get()->app_list_controller();
ASSERT_EQ(app_list_controller->GetWindow(), window_util::GetActiveWindow());
ActivateDesk(controller->GetDeskAtIndex(0));
EXPECT_EQ(window.get(), window_util::GetActiveWindow());
}
TEST_P(DesksTest, DragWindowToDesk) {
auto* controller = DesksController::Get();
NewDesk();
ASSERT_EQ(2u, controller->desks().size());
const Desk* desk_1 = controller->GetDeskAtIndex(0);
const Desk* desk_2 = controller->GetDeskAtIndex(1);
auto win1 = CreateAppWindow(gfx::Rect(0, 0, 250, 100));
auto win2 = CreateAppWindow(gfx::Rect(0, 0, 200, 150));
wm::ActivateWindow(win1.get());
EXPECT_EQ(win1.get(), window_util::GetActiveWindow());
ui::Shadow* shadow = ::wm::ShadowController::GetShadowForWindow(win1.get());
ASSERT_TRUE(shadow);
ASSERT_TRUE(shadow->layer());
EXPECT_TRUE(shadow->layer()->GetTargetVisibility());
auto* overview_controller = OverviewController::Get();
EnterOverview();
EXPECT_TRUE(overview_controller->InOverviewSession());
auto* overview_grid = GetOverviewGridForRoot(Shell::GetPrimaryRootWindow());
EXPECT_EQ(2u, overview_grid->GetNumWindows());
EXPECT_FALSE(shadow->layer()->GetTargetVisibility());
auto* overview_session = overview_controller->overview_session();
auto* overview_item = overview_session->GetOverviewItemForWindow(win1.get());
ASSERT_TRUE(overview_item);
const gfx::RectF target_bounds_before_drag = overview_item->target_bounds();
const auto* desks_bar_view = overview_grid->desks_bar_view();
ASSERT_TRUE(desks_bar_view);
ASSERT_EQ(2u, desks_bar_view->mini_views().size());
auto* desk_1_mini_view = desks_bar_view->mini_views()[0].get();
EXPECT_EQ(desk_1, desk_1_mini_view->desk());
auto* event_generator = GetEventGenerator();
DragItemToPoint(overview_item,
desk_1_mini_view->GetBoundsInScreen().CenterPoint(),
event_generator, GetParam().use_touch_gestures);
EXPECT_TRUE(overview_controller->InOverviewSession());
EXPECT_EQ(2u, overview_grid->GetNumWindows());
EXPECT_EQ(target_bounds_before_drag, overview_item->target_bounds());
EXPECT_TRUE(DoesActiveDeskContainWindow(win1.get()));
auto* desk_2_mini_view = desks_bar_view->mini_views()[1].get();
EXPECT_EQ(desk_2, desk_2_mini_view->desk());
DragItemToPoint(overview_item,
desk_2_mini_view->GetBoundsInScreen().CenterPoint(),
event_generator, GetParam().use_touch_gestures);
EXPECT_TRUE(overview_controller->InOverviewSession());
EXPECT_EQ(1u, overview_grid->GetNumWindows());
EXPECT_FALSE(DoesActiveDeskContainWindow(win1.get()));
EXPECT_TRUE(base::Contains(desk_2->windows(), win1.get()));
EXPECT_FALSE(overview_grid->drop_target());
EXPECT_EQ(overview_session->GetOverviewFocusWindow(),
window_util::GetActiveWindow());
overview_item = overview_session->GetOverviewItemForWindow(win2.get());
ASSERT_TRUE(overview_item);
const auto window_center =
gfx::ToFlooredPoint(overview_item->target_bounds().CenterPoint());
if (GetParam().use_touch_gestures) {
event_generator->GestureTapAt(window_center);
} else {
event_generator->MoveMouseTo(window_center);
event_generator->ClickLeftButton();
}
EXPECT_FALSE(overview_controller->InOverviewSession());
EXPECT_EQ(win2.get(), window_util::GetActiveWindow());
EXPECT_TRUE(shadow->layer()->GetTargetVisibility());
}
TEST_P(DesksTest, DragWindowToCloseWithThemeChange) {
auto win1 = CreateAppWindow();
auto win2 = CreateAppWindow();
EnterOverview();
auto* overview_item = Shell::Get()
->overview_controller()
->overview_session()
->GetOverviewItemForWindow(win1.get());
ASSERT_TRUE(overview_item);
auto* event_generator = GetEventGenerator();
event_generator->set_current_screen_location(
gfx::ToRoundedPoint(overview_item->target_bounds().CenterPoint()));
event_generator->PressTouch();
overview_item->item_widget()->ThemeChanged();
event_generator->MoveTouchBy(0, -50);
overview_item->item_widget()->ThemeChanged();
event_generator->MoveTouchBy(0, -200);
overview_item->item_widget()->ThemeChanged();
event_generator->ReleaseTouch();
overview_item->item_widget()->ThemeChanged();
}
TEST_P(DesksTest, DragMinimizedWindowToDesk) {
auto* controller = DesksController::Get();
NewDesk();
ASSERT_EQ(2u, controller->desks().size());
const Desk* desk_2 = controller->GetDeskAtIndex(1);
auto window = CreateAppWindow(gfx::Rect(0, 0, 250, 100));
wm::ActivateWindow(window.get());
EXPECT_EQ(window.get(), window_util::GetActiveWindow());
auto* window_state = WindowState::Get(window.get());
window_state->Minimize();
ASSERT_TRUE(window_state->IsMinimized());
auto* overview_controller = OverviewController::Get();
EnterOverview();
EXPECT_TRUE(overview_controller->InOverviewSession());
auto* overview_grid = GetOverviewGridForRoot(Shell::GetPrimaryRootWindow());
auto* overview_session = overview_controller->overview_session();
auto* overview_item =
overview_session->GetOverviewItemForWindow(window.get());
ASSERT_TRUE(overview_item);
const auto* desks_bar_view = overview_grid->desks_bar_view();
ASSERT_TRUE(desks_bar_view);
ASSERT_EQ(2u, desks_bar_view->mini_views().size());
auto* desk_2_mini_view = desks_bar_view->mini_views()[1].get();
EXPECT_EQ(desk_2, desk_2_mini_view->desk());
DragItemToPoint(overview_item,
desk_2_mini_view->GetBoundsInScreen().CenterPoint(),
GetEventGenerator(), GetParam().use_touch_gestures);
EXPECT_TRUE(overview_controller->InOverviewSession());
EXPECT_TRUE(overview_grid->empty());
EXPECT_TRUE(base::Contains(desk_2->windows(), window.get()));
EXPECT_FALSE(overview_grid->drop_target());
DeskSwitchAnimationWaiter waiter;
LeftClickOn(desk_2_mini_view);
waiter.Wait();
EXPECT_FALSE(overview_controller->InOverviewSession());
EXPECT_TRUE(desk_2->is_active());
EXPECT_FALSE(window_state->IsMinimized());
EXPECT_TRUE(window->IsVisible());
EXPECT_TRUE(window->layer()->GetTargetVisibility());
EXPECT_EQ(1.f, window->layer()->GetTargetOpacity());
}
TEST_P(DesksTest, DragAllOverviewWindowsToOtherDesksNotEndOverview) {
NewDesk();
ASSERT_EQ(2u, DesksController::Get()->desks().size());
auto win = CreateAppWindow(gfx::Rect(0, 0, 250, 100));
auto* overview_controller = OverviewController::Get();
ASSERT_TRUE(EnterOverview());
auto* overview_session = overview_controller->overview_session();
DragItemToPoint(overview_session->GetOverviewItemForWindow(win.get()),
GetOverviewGridForRoot(Shell::GetPrimaryRootWindow())
->desks_bar_view()
->mini_views()[1]
->GetBoundsInScreen()
.CenterPoint(),
GetEventGenerator(), GetParam().use_touch_gestures);
EXPECT_FALSE(DoesActiveDeskContainWindow(win.get()));
ASSERT_TRUE(overview_controller->InOverviewSession());
EXPECT_TRUE(overview_session->IsEmpty());
}
TEST_P(DesksTest, DragWindowToNonMiniViewPoints) {
auto* controller = DesksController::Get();
NewDesk();
ASSERT_EQ(2u, controller->desks().size());
auto window = CreateAppWindow(gfx::Rect(0, 0, 250, 100));
wm::ActivateWindow(window.get());
EXPECT_EQ(window.get(), window_util::GetActiveWindow());
auto* overview_controller = OverviewController::Get();
EnterOverview();
EXPECT_TRUE(overview_controller->InOverviewSession());
const auto* overview_grid =
GetOverviewGridForRoot(Shell::GetPrimaryRootWindow());
EXPECT_EQ(1u, overview_grid->GetNumWindows());
auto* overview_session = overview_controller->overview_session();
auto* overview_item =
overview_session->GetOverviewItemForWindow(window.get());
ASSERT_TRUE(overview_item);
const gfx::RectF target_bounds_before_drag = overview_item->target_bounds();
const auto* desks_bar_view = overview_grid->desks_bar_view();
ASSERT_TRUE(desks_bar_view);
DragItemToPoint(overview_item,
window->GetRootWindow()->GetBoundsInScreen().bottom_center(),
GetEventGenerator(), GetParam().use_touch_gestures);
EXPECT_TRUE(overview_controller->InOverviewSession());
EXPECT_EQ(1u, overview_grid->GetNumWindows());
EXPECT_EQ(target_bounds_before_drag, overview_item->target_bounds());
EXPECT_TRUE(DoesActiveDeskContainWindow(window.get()));
}
TEST_P(DesksTest, DragWindowAtZeroState) {
auto* controller = DesksController::Get();
auto win1 = CreateAppWindow(gfx::Rect(0, 0, 250, 100));
ASSERT_EQ(1u, controller->desks().size());
auto* overview_controller = OverviewController::Get();
EnterOverview();
ASSERT_TRUE(overview_controller->InOverviewSession());
auto* overview_grid = GetOverviewGridForRoot(Shell::GetPrimaryRootWindow());
const auto* desks_bar_view = overview_grid->desks_bar_view();
ASSERT_TRUE(desks_bar_view);
ASSERT_EQ(0u, desks_bar_view->mini_views().size());
auto* default_desk_button = desks_bar_view->default_desk_button();
auto* new_desk_button = desks_bar_view->new_desk_button();
EXPECT_TRUE(default_desk_button->GetVisible());
VerifyZeroStateNewDeskButtonVisibility(desks_bar_view, true);
VerifyExpandedStateNewDeskButtonVisibility(desks_bar_view, false);
auto* overview_item1 = overview_grid->GetOverviewItemContaining(win1.get());
auto* event_generator = GetEventGenerator();
DragItemToPoint(
overview_item1,
gfx::ToRoundedPoint(overview_item1->target_bounds().CenterPoint() +
gfx::Vector2d(100, -100)),
event_generator,
false, false);
EXPECT_FALSE(default_desk_button->GetVisible());
VerifyZeroStateNewDeskButtonVisibility(desks_bar_view, false);
VerifyExpandedStateNewDeskButtonVisibility(desks_bar_view, true);
const gfx::Point new_desk_button_center_point =
new_desk_button->GetBoundsInScreen().CenterPoint();
const gfx::Point new_desk_button_bottom_left =
new_desk_button->GetBoundsInScreen().bottom_left();
DragItemToPoint(overview_item1,
new_desk_button_bottom_left + gfx::Vector2d(10, -10),
event_generator, false,
false);
WaitForMilliseconds(200);
EXPECT_EQ(DeskIconButton::State::kExpanded, new_desk_button->state());
EXPECT_FALSE(IsLazyInitViewVisible(desks_bar_view->new_desk_button_label()));
overview_controller->overview_session()
->window_drag_controller()
->new_desk_button_scale_up_timer_for_test()
->FireNow();
RunScheduledLayoutForAllOverviewDeskBars();
EXPECT_EQ(DeskIconButton::State::kActive, new_desk_button->state());
EXPECT_TRUE(IsLazyInitViewVisible(desks_bar_view->new_desk_button_label()));
DragItemToPoint(overview_item1,
new_desk_button_center_point + gfx::Vector2d(10, 10),
event_generator, false,
false);
event_generator->ReleaseLeftButton();
RunScheduledLayoutForAllOverviewDeskBars();
EXPECT_TRUE(overview_controller->InOverviewSession());
EXPECT_EQ(2u, desks_bar_view->mini_views().size());
EXPECT_EQ(2u, controller->desks().size());
EXPECT_TRUE(
base::Contains(controller->GetDeskAtIndex(1)->windows(), win1.get()));
EXPECT_EQ(DesksController::Get()->active_desk(),
controller->GetDeskAtIndex(0));
EXPECT_EQ(0u, overview_grid->GetNumWindows());
}
TEST_P(DesksTest, DragWindowAtZeroStateWithoutDroppingItOnTheNewDesk) {
auto* controller = DesksController::Get();
auto win1 = CreateAppWindow(gfx::Rect(0, 0, 250, 100));
ASSERT_EQ(1u, controller->desks().size());
auto* overview_controller = OverviewController::Get();
EnterOverview();
ASSERT_TRUE(overview_controller->InOverviewSession());
auto* overview_grid = GetOverviewGridForRoot(Shell::GetPrimaryRootWindow());
const auto* desks_bar_view = overview_grid->desks_bar_view();
ASSERT_TRUE(desks_bar_view);
auto* default_desk_button = desks_bar_view->default_desk_button();
auto* new_desk_button = desks_bar_view->new_desk_button();
EXPECT_TRUE(default_desk_button->GetVisible());
VerifyZeroStateNewDeskButtonVisibility(desks_bar_view, true);
VerifyExpandedStateNewDeskButtonVisibility(desks_bar_view, false);
auto* overview_item1 = overview_grid->GetOverviewItemContaining(win1.get());
auto* event_generator = GetEventGenerator();
DragItemToPoint(
overview_item1,
gfx::ToRoundedPoint(overview_item1->target_bounds().CenterPoint() +
gfx::Vector2d(100, -100)),
event_generator,
false, false);
EXPECT_FALSE(desks_bar_view->IsZeroState());
EXPECT_EQ(DeskIconButton::State::kExpanded, new_desk_button->state());
EXPECT_FALSE(IsLazyInitViewVisible(desks_bar_view->new_desk_button_label()));
const gfx::Point new_desk_button_center_point =
new_desk_button->GetBoundsInScreen().CenterPoint();
DragItemToPoint(overview_item1,
gfx::Point(new_desk_button_center_point.x() + 10,
new_desk_button_center_point.y() + 10),
event_generator, false,
false);
overview_controller->overview_session()
->window_drag_controller()
->new_desk_button_scale_up_timer_for_test()
->FireNow();
RunScheduledLayoutForAllOverviewDeskBars();
EXPECT_EQ(DeskIconButton::State::kActive, new_desk_button->state());
EXPECT_TRUE(IsLazyInitViewVisible(desks_bar_view->new_desk_button_label()));
const gfx::Point expanded_new_desk_button_center_point =
new_desk_button->GetBoundsInScreen().CenterPoint();
DragItemToPoint(overview_item1,
gfx::Point(expanded_new_desk_button_center_point.x() + 200,
expanded_new_desk_button_center_point.y() + 200),
event_generator, false, true);
RunScheduledLayoutForAllOverviewDeskBars();
EXPECT_FALSE(desks_bar_view->IsZeroState());
EXPECT_FALSE(IsLazyInitViewVisible(desks_bar_view->new_desk_button_label()));
EXPECT_EQ(1u, controller->desks().size());
EXPECT_TRUE(
base::Contains(controller->GetDeskAtIndex(0)->windows(), win1.get()));
}
TEST_P(DesksTest, DragWindowAtExpandedState) {
auto* controller = DesksController::Get();
auto win1 = CreateAppWindow(gfx::Rect(0, 0, 250, 100));
NewDesk();
ASSERT_EQ(2u, controller->desks().size());
auto* overview_controller = OverviewController::Get();
EnterOverview();
ASSERT_TRUE(overview_controller->InOverviewSession());
const auto* desks_bar_view =
GetOverviewGridForRoot(Shell::GetPrimaryRootWindow())->desks_bar_view();
ASSERT_TRUE(desks_bar_view);
ASSERT_EQ(2u, desks_bar_view->mini_views().size());
auto* new_desk_button = desks_bar_view->new_desk_button();
VerifyExpandedStateNewDeskButtonVisibility(desks_bar_view, true);
auto* event_generator = GetEventGenerator();
DragItemToPoint(
overview_controller->overview_session()->GetOverviewItemForWindow(
win1.get()),
new_desk_button->GetBoundsInScreen().CenterPoint(), GetEventGenerator(),
false,
false);
overview_controller->overview_session()
->window_drag_controller()
->new_desk_button_scale_up_timer_for_test()
->FireNow();
event_generator->ReleaseLeftButton();
EXPECT_TRUE(overview_controller->InOverviewSession());
EXPECT_EQ(3u, desks_bar_view->mini_views().size());
EXPECT_EQ(3u, controller->desks().size());
EXPECT_TRUE(
base::Contains(controller->GetDeskAtIndex(2)->windows(), win1.get()));
}
TEST_P(DesksTest, DragWindowAtMaximumDesksState) {
UpdateDisplay("800x801");
auto* controller = DesksController::Get();
auto win1 = CreateAppWindow(gfx::Rect(0, 0, 250, 100));
while (controller->desks().size() < desks_util::GetMaxNumberOfDesks()) {
NewDesk();
}
ASSERT_EQ(desks_util::GetMaxNumberOfDesks(), controller->desks().size());
auto* overview_controller = OverviewController::Get();
EnterOverview();
ASSERT_TRUE(overview_controller->InOverviewSession());
const auto* desks_bar_view =
GetOverviewGridForRoot(Shell::GetPrimaryRootWindow())->desks_bar_view();
ASSERT_TRUE(desks_bar_view);
auto* event_generator = GetEventGenerator();
for (int i = 0; i != 3; ++i) {
TryScrollOverviewDeskBar(DeskBarScrollDirection::kRight);
}
const gfx::Point overview_item_center =
gfx::ToRoundedPoint(overview_controller->overview_session()
->GetOverviewItemForWindow(win1.get())
->target_bounds()
.CenterPoint());
event_generator->set_current_screen_location(overview_item_center);
event_generator->PressLeftButton();
event_generator->MoveMouseBy(20, 0);
event_generator->MoveMouseTo(
desks_bar_view->new_desk_button()->GetBoundsInScreen().CenterPoint());
event_generator->ReleaseLeftButton();
ASSERT_TRUE(overview_controller->InOverviewSession());
EXPECT_EQ(desks_util::GetMaxNumberOfDesks(),
desks_bar_view->mini_views().size());
EXPECT_EQ(desks_util::GetMaxNumberOfDesks(), controller->desks().size());
EXPECT_TRUE(
base::Contains(controller->GetDeskAtIndex(0)->windows(), win1.get()));
}
TEST_P(DesksTest, MruWindowTracker) {
auto win0 = CreateAppWindow(gfx::Rect(0, 0, 250, 100));
auto win1 = CreateAppWindow(gfx::Rect(50, 50, 200, 200));
auto* controller = DesksController::Get();
NewDesk();
ASSERT_EQ(2u, controller->desks().size());
const Desk* desk_2 = controller->GetDeskAtIndex(1);
ActivateDesk(desk_2);
EXPECT_EQ(desk_2, controller->active_desk());
auto win2 = CreateAppWindow(gfx::Rect(0, 0, 300, 200));
auto win3 = CreateAppWindow(gfx::Rect(10, 30, 400, 200));
auto* mru_window_tracker = Shell::Get()->mru_window_tracker();
auto window_list = mru_window_tracker->BuildWindowForCycleList(kActiveDesk);
ASSERT_EQ(2u, window_list.size());
EXPECT_EQ(win3.get(), window_list[0]);
EXPECT_EQ(win2.get(), window_list[1]);
window_list = mru_window_tracker->BuildWindowForCycleList(kAllDesks);
ASSERT_EQ(4u, window_list.size());
EXPECT_EQ(win3.get(), window_list[0]);
EXPECT_EQ(win2.get(), window_list[1]);
EXPECT_EQ(win1.get(), window_list[2]);
EXPECT_EQ(win0.get(), window_list[3]);
Desk* desk_1 = controller->GetDeskAtIndex(0);
ActivateDesk(desk_1);
window_list = mru_window_tracker->BuildWindowForCycleList(kActiveDesk);
ASSERT_EQ(2u, window_list.size());
EXPECT_EQ(win1.get(), window_list[0]);
EXPECT_EQ(win0.get(), window_list[1]);
window_list = mru_window_tracker->BuildWindowForCycleList(kAllDesks);
ASSERT_EQ(4u, window_list.size());
EXPECT_EQ(win1.get(), window_list[0]);
EXPECT_EQ(win3.get(), window_list[1]);
EXPECT_EQ(win2.get(), window_list[2]);
EXPECT_EQ(win0.get(), window_list[3]);
}
TEST_P(DesksTest, NextActivatable) {
auto win0 = CreateAppWindow(gfx::Rect(0, 0, 250, 100));
auto win1 = CreateAppWindow(gfx::Rect(50, 50, 200, 200));
auto* controller = DesksController::Get();
NewDesk();
ASSERT_EQ(2u, controller->desks().size());
const Desk* desk_2 = controller->GetDeskAtIndex(1);
ActivateDesk(desk_2);
EXPECT_EQ(desk_2, controller->active_desk());
auto win2 = CreateAppWindow(gfx::Rect(0, 0, 300, 200));
auto win3 = CreateAppWindow(gfx::Rect(10, 30, 400, 200));
EXPECT_EQ(win3.get(), window_util::GetActiveWindow());
wm::DeactivateWindow(win3.get());
EXPECT_EQ(win2.get(), window_util::GetActiveWindow());
wm::DeactivateWindow(win2.get());
EXPECT_EQ(win3.get(), window_util::GetActiveWindow());
Desk* desk_1 = controller->GetDeskAtIndex(0);
ActivateDesk(desk_1);
EXPECT_EQ(win1.get(), window_util::GetActiveWindow());
win1.reset();
EXPECT_EQ(win0.get(), window_util::GetActiveWindow());
win0.reset();
EXPECT_EQ(nullptr, window_util::GetActiveWindow());
}
TEST_P(DesksTest, NoMiniViewsUpdateOnOverviewEnter) {
auto* controller = DesksController::Get();
NewDesk();
ASSERT_EQ(2u, controller->desks().size());
auto* desk_1 = controller->GetDeskAtIndex(0);
auto* desk_2 = controller->GetDeskAtIndex(1);
auto win0 = CreateAppWindow(gfx::Rect(0, 0, 250, 100));
auto win1 = CreateAppWindow(gfx::Rect(50, 50, 200, 200));
wm::ActivateWindow(win1.get());
EXPECT_EQ(win1.get(), window_util::GetActiveWindow());
TestDeskObserver desk_1_observer;
TestDeskObserver desk_2_observer;
desk_1->AddObserver(&desk_1_observer);
desk_2->AddObserver(&desk_2_observer);
EXPECT_EQ(0, desk_1_observer.notify_counts());
EXPECT_EQ(0, desk_2_observer.notify_counts());
EnterOverview();
EXPECT_TRUE(OverviewController::Get()->InOverviewSession());
EXPECT_EQ(0, desk_1_observer.notify_counts());
EXPECT_EQ(0, desk_2_observer.notify_counts());
desk_1->RemoveObserver(&desk_1_observer);
desk_2->RemoveObserver(&desk_2_observer);
}
TEST_P(DesksTest, ConsecutiveDailyVisitsMetric) {
constexpr char kConsecutiveDailyVisitsHistogram[] =
"Ash.Desks.ConsecutiveDailyVisits";
auto* desks_controller = DesksController::Get();
base::HistogramTester histogram_tester;
base::SimpleTestClock test_clock;
test_clock.SetNow(base::Time::Now().LocalMidnight());
test_clock.Advance(base::Hours(1));
auto* active_desk = desks_controller->active_desk();
desks_restore_util::OverrideClockForTesting(&test_clock);
DesksTestApi::ResetDeskVisitedMetrics(const_cast<Desk*>(active_desk));
EXPECT_EQ(
0u,
histogram_tester.GetAllSamples(kConsecutiveDailyVisitsHistogram).size());
active_desk = desks_controller->active_desk();
NewDesk();
ASSERT_EQ(active_desk, desks_controller->active_desk());
test_clock.Advance(base::Days(2));
RemoveDesk(active_desk);
histogram_tester.ExpectBucketCount(kConsecutiveDailyVisitsHistogram, 3, 1);
EXPECT_EQ(
1u,
histogram_tester.GetAllSamples(kConsecutiveDailyVisitsHistogram).size());
active_desk = desks_controller->active_desk();
NewDesk();
RemoveDesk(active_desk);
histogram_tester.ExpectBucketCount(kConsecutiveDailyVisitsHistogram, 1, 1);
EXPECT_EQ(
2u,
histogram_tester.GetAllSamples(kConsecutiveDailyVisitsHistogram).size());
NewDesk();
ActivateDesk(desks_controller->GetNextDesk());
test_clock.Advance(base::Days(2));
ActivateDesk(desks_controller->GetPreviousDesk());
histogram_tester.ExpectBucketCount(kConsecutiveDailyVisitsHistogram, 1, 2);
EXPECT_EQ(
2u,
histogram_tester.GetAllSamples(kConsecutiveDailyVisitsHistogram).size());
test_clock.Advance(base::Days(-2));
ActivateDesk(desks_controller->GetNextDesk());
active_desk = desks_controller->active_desk();
const int current_date = desks_restore_util::GetDaysFromLocalEpoch();
EXPECT_EQ(current_date, active_desk->first_day_visited());
EXPECT_EQ(current_date, active_desk->last_day_visited());
desks_restore_util::OverrideClockForTesting(nullptr);
}
TEST_P(DesksTest, NewDeskButtonStateAndColor) {
auto* controller = DesksController::Get();
NewDesk();
ASSERT_EQ(2u, controller->desks().size());
EnterOverview();
const auto* overview_grid =
GetOverviewGridForRoot(Shell::GetPrimaryRootWindow());
const auto* desks_bar_view = overview_grid->desks_bar_view();
ASSERT_TRUE(desks_bar_view);
const auto* new_desk_button = desks_bar_view->new_desk_button();
auto* color_provider = new_desk_button->GetColorProvider();
SkColor background_color =
color_provider->GetColor(cros_tokens::kCrosSysPrimary);
auto get_background_color([](const views::View* view) {
return view->GetBackground()->color().ResolveToSkColor(
view->GetColorProvider());
});
const SkColor disabled_background_color =
ColorUtil::GetDisabledColor(background_color);
EXPECT_TRUE(new_desk_button->GetEnabled());
EXPECT_EQ(background_color,
get_background_color(desks_bar_view->new_desk_button()));
LeftClickOn(new_desk_button);
EXPECT_TRUE(new_desk_button->GetEnabled());
EXPECT_EQ(background_color,
get_background_color(desks_bar_view->new_desk_button()));
size_t prev_size = controller->desks().size();
while (controller->CanCreateDesks()) {
LeftClickOn(new_desk_button);
EXPECT_EQ(prev_size + 1, controller->desks().size());
prev_size = controller->desks().size();
RunScheduledLayoutForAllOverviewDeskBars();
TryScrollOverviewDeskBar(DeskBarScrollDirection::kRight);
RunScheduledLayoutForAllOverviewDeskBars();
}
EXPECT_FALSE(new_desk_button->GetEnabled());
EXPECT_EQ(disabled_background_color,
get_background_color(desks_bar_view->new_desk_button()));
}
TEST_P(DesksTest, FullscreenStateUpdatedAcrossDesks) {
FullScreenStateObserver full_screen_state_observer;
auto* controller = DesksController::Get();
WMEvent event_toggle_fullscreen(WM_EVENT_TOGGLE_FULLSCREEN);
NewDesk();
EXPECT_EQ(2u, controller->desks().size());
std::vector<std::unique_ptr<aura::Window>> windows;
for (int i = 0; i < 2; i++) {
windows.push_back(CreateAppWindow());
controller->SendToDeskAtIndex(windows[i].get(), i);
EXPECT_EQ(i, windows[i]->GetProperty(aura::client::kWindowWorkspaceKey));
}
WindowState* win0_state = WindowState::Get(windows[0].get());
WindowState* win1_state = WindowState::Get(windows[1].get());
EXPECT_FALSE(full_screen_state_observer.is_fullscreen());
win0_state->OnWMEvent(&event_toggle_fullscreen);
EXPECT_EQ(windows[0].get(), window_util::GetActiveWindow());
EXPECT_TRUE(win0_state->IsFullscreen());
EXPECT_TRUE(full_screen_state_observer.is_fullscreen());
ActivateDesk(controller->GetDeskAtIndex(1));
EXPECT_EQ(windows[1].get(), window_util::GetActiveWindow());
EXPECT_FALSE(win1_state->IsFullscreen());
EXPECT_FALSE(full_screen_state_observer.is_fullscreen());
ActivateDesk(controller->GetDeskAtIndex(0));
EXPECT_EQ(windows[0].get(), window_util::GetActiveWindow());
EXPECT_TRUE(win0_state->IsFullscreen());
EXPECT_TRUE(full_screen_state_observer.is_fullscreen());
}
TEST_P(DesksTest, AnimationLatencyDeskActivation) {
NewDesk();
auto* controller = DesksController::Get();
ASSERT_EQ(2u, controller->desks().size());
base::HistogramTester histogram_tester;
ActivateDesk(controller->GetDeskAtIndex(1));
histogram_tester.ExpectTotalCount("Ash.Desks.AnimationLatency.DeskActivation",
1);
}
TEST_P(DesksTest, AnimationLatencyDeskRemoval) {
NewDesk();
auto* controller = DesksController::Get();
ASSERT_EQ(2u, controller->desks().size());
base::HistogramTester histogram_tester;
RemoveDesk(controller->GetDeskAtIndex(0));
histogram_tester.ExpectTotalCount("Ash.Desks.AnimationLatency.DeskRemoval",
1);
}
TEST_P(DesksTest, MruFocusedOnDeskSwitchDualDisplay) {
UpdateDisplay("700x600,400x500");
auto* controller = DesksController::Get();
auto roots = Shell::GetAllRootWindows();
auto win1 = CreateAppWindow(gfx::Rect(50, 50, 200, 200));
auto win2 = CreateAppWindow(gfx::Rect(750, 50, 200, 200));
ASSERT_EQ(win1->GetRootWindow(), roots[0]);
ASSERT_EQ(win2->GetRootWindow(), roots[1]);
win2->Focus();
NewDesk();
const Desk* desk_1 = controller->GetDeskAtIndex(0);
const Desk* desk_2 = controller->GetDeskAtIndex(1);
ActivateDesk(desk_2);
auto win3 = CreateAppWindow(gfx::Rect(50, 50, 200, 200));
auto win4 = CreateAppWindow(gfx::Rect(750, 50, 200, 200));
ASSERT_EQ(win3->GetRootWindow(), roots[0]);
ASSERT_EQ(win4->GetRootWindow(), roots[1]);
win3->Focus();
ActivateDesk(desk_1);
ASSERT_TRUE(win2->HasFocus());
ASSERT_FALSE(win1->HasFocus());
ASSERT_FALSE(win3->HasFocus());
ASSERT_FALSE(win4->HasFocus());
ActivateDesk(desk_2);
ASSERT_TRUE(win3->HasFocus());
ASSERT_FALSE(win1->HasFocus());
ASSERT_FALSE(win2->HasFocus());
ASSERT_FALSE(win4->HasFocus());
}
TEST_P(DesksTest, RemoveDisplayWhileSwitchingDesks) {
auto* controller = DesksController::Get();
UpdateDisplay("800x600,800x600");
NewDesk();
gfx::ScopedAnimationDurationScaleMode animation_scale(
gfx::ScopedAnimationDurationScaleMode::NON_ZERO_DURATION);
DeskSwitchAnimationWaiter desk_switch_waiter;
const Desk* desk_2 = controller->GetDeskAtIndex(1);
controller->ActivateDesk(desk_2, DesksSwitchSource::kMiniViewButton);
UpdateDisplay("800x600");
desk_switch_waiter.Wait();
EXPECT_EQ(desk_2, controller->active_desk());
}
TEST_P(DesksTest, AddDeskWhileExitingOverview) {
UpdateDisplay("800x600");
EnterOverview();
EXPECT_TRUE(OverviewController::Get()->InOverviewSession());
gfx::ScopedAnimationDurationScaleMode animation_scale(
gfx::ScopedAnimationDurationScaleMode::NON_ZERO_DURATION);
ExitOverview();
NewDesk();
}
TEST_P(DesksTest, EndingDeskShouldNotOccludeStartingDesk) {
UpdateDisplay("600x400");
auto* root = Shell::GetPrimaryRootWindow();
auto* controller = DesksController::Get();
NewDesk();
ASSERT_EQ(2u, controller->desks().size());
const Desk* desk1 = controller->GetDeskAtIndex(0);
const Desk* desk2 = controller->GetDeskAtIndex(1);
auto* desk1_container = desk1->GetDeskContainerForRoot(root);
auto* desk2_container = desk2->GetDeskContainerForRoot(root);
ASSERT_TRUE(desk1_container->IsVisible());
ASSERT_FALSE(desk2_container->IsVisible());
ASSERT_EQ(desks_util::GetActiveDeskContainerForRoot(root), desk1_container);
const auto win1_bounds = gfx::Rect{20, 20, 100, 100};
const auto win2_bounds = gfx::Rect{10, 10, 200, 200};
std::unique_ptr<aura::Window> win1 = CreateAppWindow(win1_bounds);
std::unique_ptr<aura::Window> win2 = CreateAppWindow(win2_bounds);
win1->TrackOcclusionState();
win2->TrackOcclusionState();
win1->Show();
win2->Show();
wm::ActivateWindow(win2.get());
ASSERT_EQ(win1->GetOcclusionState(), aura::Window::OcclusionState::OCCLUDED);
ASSERT_EQ(win2->GetOcclusionState(), aura::Window::OcclusionState::VISIBLE);
wm::ActivateWindow(win1.get());
ASSERT_EQ(win1->GetOcclusionState(), aura::Window::OcclusionState::VISIBLE);
ASSERT_EQ(win2->GetOcclusionState(), aura::Window::OcclusionState::VISIBLE);
controller->SendToDeskAtIndex(win2.get(), 1);
ASSERT_EQ(win1->GetOcclusionState(), aura::Window::OcclusionState::VISIBLE);
ASSERT_EQ(win2->GetOcclusionState(), aura::Window::OcclusionState::HIDDEN);
DeskSwitchAnimationWaiter animation_waiter;
controller->ActivateDesk(desk2, DesksSwitchSource::kDeskSwitchShortcut);
EXPECT_TRUE(desk1_container->IsVisible());
EXPECT_TRUE(desk2_container->IsVisible());
EXPECT_EQ(win1->GetOcclusionState(), aura::Window::OcclusionState::VISIBLE);
EXPECT_EQ(win2->GetOcclusionState(), aura::Window::OcclusionState::HIDDEN);
base::RunLoop run_loop;
DeskAnimationBase* animation = DesksController::Get()->animation();
ASSERT_TRUE(animation);
auto* desk_switch_animator =
animation->GetDeskSwitchAnimatorAtIndexForTesting(0);
ASSERT_TRUE(desk_switch_animator);
RootWindowDeskSwitchAnimatorTestApi(desk_switch_animator)
.SetOnStartingScreenshotTakenCallback(run_loop.QuitClosure());
run_loop.Run();
EXPECT_EQ(desks_util::GetActiveDeskContainerForRoot(root), desk2_container);
EXPECT_FALSE(desk1_container->IsVisible());
EXPECT_TRUE(desk2_container->IsVisible());
EXPECT_EQ(win1->GetOcclusionState(), aura::Window::OcclusionState::HIDDEN);
EXPECT_EQ(win2->GetOcclusionState(), aura::Window::OcclusionState::VISIBLE);
animation_waiter.Wait();
}
class DesksWithMultiDisplayOverview : public AshTestBase {
public:
DesksWithMultiDisplayOverview() = default;
~DesksWithMultiDisplayOverview() override = default;
void SetUp() override {
AshTestBase::SetUp();
UpdateDisplay("700x600,400x500");
NewDesk();
}
};
TEST_F(DesksWithMultiDisplayOverview, DropOnSameDeskInOtherDisplay) {
auto roots = Shell::GetAllRootWindows();
ASSERT_EQ(2u, roots.size());
auto win = CreateAppWindow(gfx::Rect(0, 0, 250, 100));
auto* overview_controller = OverviewController::Get();
EnterOverview();
EXPECT_TRUE(overview_controller->InOverviewSession());
auto* overview_session = overview_controller->overview_session();
auto* overview_item = overview_session->GetOverviewItemForWindow(win.get());
ASSERT_TRUE(overview_item);
auto* grid1 = GetOverviewGridForRoot(roots[0]);
auto* grid2 = GetOverviewGridForRoot(roots[1]);
EXPECT_EQ(1u, grid1->GetNumWindows());
EXPECT_EQ(grid1, overview_item->overview_grid());
EXPECT_EQ(0u, grid2->GetNumWindows());
const auto* desks_bar_view = grid2->desks_bar_view();
ASSERT_TRUE(desks_bar_view);
ASSERT_EQ(2u, desks_bar_view->mini_views().size());
auto* desk_1_mini_view = desks_bar_view->mini_views()[0].get();
auto* event_generator = GetEventGenerator();
DragItemToPoint(overview_item,
desk_1_mini_view->GetBoundsInScreen().CenterPoint(),
event_generator,
false);
EXPECT_TRUE(overview_controller->InOverviewSession());
overview_item = overview_session->GetOverviewItemForWindow(win.get());
ASSERT_TRUE(overview_item);
EXPECT_EQ(0u, grid1->GetNumWindows());
EXPECT_EQ(grid2, overview_item->overview_grid());
EXPECT_EQ(1u, grid2->GetNumWindows());
EXPECT_TRUE(DoesActiveDeskContainWindow(win.get()));
EXPECT_EQ(roots[1], win->GetRootWindow());
}
TEST_F(DesksWithMultiDisplayOverview, DropOnOtherDeskInOtherDisplay) {
auto roots = Shell::GetAllRootWindows();
ASSERT_EQ(2u, roots.size());
auto win = CreateAppWindow(gfx::Rect(0, 0, 250, 100));
auto* overview_controller = OverviewController::Get();
EnterOverview();
EXPECT_TRUE(overview_controller->InOverviewSession());
auto* overview_session = overview_controller->overview_session();
auto* overview_item = overview_session->GetOverviewItemForWindow(win.get());
ASSERT_TRUE(overview_item);
auto* grid1 = GetOverviewGridForRoot(roots[0]);
auto* grid2 = GetOverviewGridForRoot(roots[1]);
EXPECT_EQ(1u, grid1->GetNumWindows());
EXPECT_EQ(grid1, overview_item->overview_grid());
EXPECT_EQ(0u, grid2->GetNumWindows());
const auto* desks_bar_view = grid2->desks_bar_view();
auto* desk_2_mini_view = desks_bar_view->mini_views()[1].get();
gfx::Point desk_2_mini_view_center =
desk_2_mini_view->GetBoundsInScreen().CenterPoint();
DragItemToPoint(overview_item, desk_2_mini_view_center, GetEventGenerator(),
false,
false);
EXPECT_TRUE(overview_controller->InOverviewSession());
EXPECT_EQ(
SplitViewDragIndicators::WindowDraggingState::kFromOverview,
grid2->split_view_drag_indicators()->current_window_dragging_state());
desk_2_mini_view_center = desk_2_mini_view->GetBoundsInScreen().CenterPoint();
DragItemToPoint(overview_item, desk_2_mini_view_center, GetEventGenerator(),
false,
true);
EXPECT_TRUE(overview_controller->InOverviewSession());
overview_item = overview_session->GetOverviewItemForWindow(win.get());
ASSERT_FALSE(overview_item);
EXPECT_EQ(0u, grid1->GetNumWindows());
EXPECT_EQ(0u, grid2->GetNumWindows());
EXPECT_FALSE(DoesActiveDeskContainWindow(win.get()));
EXPECT_EQ(roots[1], win->GetRootWindow());
EXPECT_FALSE(win->IsVisible());
auto* controller = DesksController::Get();
const Desk* desk_2 = controller->GetDeskAtIndex(1);
EXPECT_TRUE(base::Contains(desk_2->windows(), win.get()));
}
TEST_F(DesksWithMultiDisplayOverview, CloseDeskBeforeAnimationFinishes) {
gfx::ScopedAnimationDurationScaleMode animation_scale(
gfx::ScopedAnimationDurationScaleMode::NON_ZERO_DURATION);
auto win0 = CreateAppWindow(gfx::Rect(0, 0, 250, 100));
const WMEvent toggle_maximize_event(WM_EVENT_TOGGLE_MAXIMIZE);
WindowState::Get(win0.get())->OnWMEvent(&toggle_maximize_event);
ASSERT_TRUE(WindowState::Get(win0.get())->IsMaximized());
EnterOverview();
auto* overview_controller = OverviewController::Get();
ASSERT_TRUE(overview_controller->InOverviewSession());
auto root_windows = Shell::GetAllRootWindows();
ASSERT_EQ(2u, root_windows.size());
const auto* desks_bar_view_1 =
GetOverviewGridForRoot(root_windows[0])->desks_bar_view();
ASSERT_EQ(2u, desks_bar_view_1->mini_views().size());
ASSERT_EQ(nullptr, GetOverviewGridForRoot(root_windows[1])->desks_bar_view());
views::NamedWidgetShownWaiter waiter(views::test::AnyWidgetTestPasskey{},
"OverviewDeskBarWidget");
auto* desk_1_mini_view = desks_bar_view_1->mini_views()[0].get();
CloseDeskFromMiniView(desk_1_mini_view, GetEventGenerator());
waiter.WaitIfNeededAndGet();
ASSERT_TRUE(overview_controller->InOverviewSession());
ASSERT_FALSE(desks_bar_view_1->IsZeroState());
const auto* desks_bar_view_2 =
GetOverviewGridForRoot(root_windows[1])->desks_bar_view();
ASSERT_TRUE(desks_bar_view_2->IsZeroState());
}
PrefService* GetPrimaryUserPrefService() {
return Shell::Get()->session_controller()->GetPrimaryUserPrefService();
}
std::vector<std::string> GetDeskRestoreNames(PrefService* user_prefs) {
const base::Value::List& desk_restore_names =
user_prefs->GetList(prefs::kDesksNamesList);
std::vector<std::string> names;
for (const auto& value : desk_restore_names) {
names.push_back(value.GetString());
}
return names;
}
std::vector<base::Uuid> GetDeskRestoreGuids(PrefService* user_prefs) {
const base::Value::List& desks_restore_guids =
user_prefs->GetList(prefs::kDesksGuidsList);
std::vector<base::Uuid> guids;
for (const base::Value& value : desks_restore_guids) {
guids.emplace_back(base::Uuid::ParseLowercase(value.GetString()));
}
return guids;
}
class DesksEditableNamesTest : public DesksTest {
public:
DesksEditableNamesTest() = default;
DesksEditableNamesTest(const DesksEditableNamesTest&) = delete;
DesksEditableNamesTest& operator=(const DesksEditableNamesTest&) = delete;
~DesksEditableNamesTest() override = default;
DesksController* controller() { return controller_; }
OverviewGrid* overview_grid() { return overview_grid_; }
const DeskBarViewBase* desks_bar_view() { return desks_bar_view_; }
void SetUp() override {
DesksTest::SetUp();
NewDesk();
controller_ = DesksController::Get();
EnterOverview();
overview_grid_ = GetOverviewGridForRoot(Shell::GetPrimaryRootWindow());
desks_bar_view_ = overview_grid_->desks_bar_view();
ASSERT_TRUE(desks_bar_view_);
}
void ClickOnDeskNameViewAtIndex(size_t index) {
ASSERT_TRUE(OverviewController::Get()->InOverviewSession());
ASSERT_LT(index, desks_bar_view_->mini_views().size());
auto* desk_name_view =
desks_bar_view_->mini_views()[index]->desk_name_view();
auto* generator = GetEventGenerator();
generator->MoveMouseTo(desk_name_view->GetBoundsInScreen().CenterPoint());
generator->ClickLeftButton();
}
private:
raw_ptr<DesksController, DanglingUntriaged> controller_ = nullptr;
raw_ptr<OverviewGrid, DanglingUntriaged> overview_grid_ = nullptr;
raw_ptr<const DeskBarViewBase, DanglingUntriaged> desks_bar_view_ = nullptr;
};
TEST_P(DesksEditableNamesTest, DefaultNameChangeAborted) {
ASSERT_EQ(2u, controller()->desks().size());
ASSERT_TRUE(OverviewController::Get()->InOverviewSession());
auto* desk_name_view_2 = desks_bar_view()->mini_views()[1]->desk_name_view();
EXPECT_FALSE(overview_grid()->IsDeskNameBeingModified());
ClickOnDeskNameViewAtIndex(1);
EXPECT_TRUE(overview_grid()->IsDeskNameBeingModified());
EXPECT_TRUE(desk_name_view_2->HasFocus());
PressAndReleaseKey(ui::VKEY_RETURN);
EXPECT_FALSE(overview_grid()->IsDeskNameBeingModified());
EXPECT_FALSE(desk_name_view_2->HasFocus());
auto* desk_2 = controller()->GetDeskAtIndex(1);
EXPECT_FALSE(desk_2->is_name_set_by_user());
EXPECT_THAT(GetDeskRestoreNames(GetPrimaryUserPrefService()),
ElementsAre("", ""));
}
TEST_P(DesksEditableNamesTest, NamesSetByUsersAreNotOverwritten) {
ASSERT_EQ(2u, controller()->desks().size());
ASSERT_TRUE(OverviewController::Get()->InOverviewSession());
ClickOnDeskNameViewAtIndex(0);
PressAndReleaseKey(ui::VKEY_A, ui::EF_CONTROL_DOWN);
PressAndReleaseKey(ui::VKEY_BACK);
PressAndReleaseKey(ui::VKEY_SPACE);
PressAndReleaseKey(ui::VKEY_C);
PressAndReleaseKey(ui::VKEY_O);
PressAndReleaseKey(ui::VKEY_D);
PressAndReleaseKey(ui::VKEY_E);
PressAndReleaseKey(ui::VKEY_SPACE);
PressAndReleaseKey(ui::VKEY_SPACE);
PressAndReleaseKey(ui::VKEY_RETURN);
auto* desk_1 = controller()->GetDeskAtIndex(0);
auto* desk_2 = controller()->GetDeskAtIndex(1);
EXPECT_EQ(u"code", desk_1->name());
EXPECT_EQ(u"Desk 2", desk_2->name());
EXPECT_TRUE(desk_1->is_name_set_by_user());
EXPECT_FALSE(desk_2->is_name_set_by_user());
EXPECT_THAT(GetDeskRestoreNames(GetPrimaryUserPrefService()),
ElementsAre("code", ""));
NewDesk();
auto* desk_3 = controller()->GetDeskAtIndex(2);
EXPECT_EQ(u"Desk 3", desk_3->name());
EXPECT_TRUE(desk_1->is_name_set_by_user());
EXPECT_FALSE(desk_2->is_name_set_by_user());
EXPECT_FALSE(desk_3->is_name_set_by_user());
EXPECT_THAT(GetDeskRestoreNames(GetPrimaryUserPrefService()),
ElementsAre("code", "", ""));
RemoveDesk(desk_2);
EXPECT_TRUE(desk_1->is_name_set_by_user());
EXPECT_FALSE(desk_3->is_name_set_by_user());
EXPECT_EQ(u"Desk 2", desk_3->name());
EXPECT_THAT(GetDeskRestoreNames(GetPrimaryUserPrefService()),
ElementsAre("code", ""));
ExitOverview();
EnterOverview();
EXPECT_TRUE(desk_1->is_name_set_by_user());
EXPECT_FALSE(desk_3->is_name_set_by_user());
EXPECT_EQ(u"code", desk_1->name());
EXPECT_EQ(u"Desk 2", desk_3->name());
}
TEST_P(DesksEditableNamesTest, DontAllowEmptyNames) {
ASSERT_EQ(2u, controller()->desks().size());
ASSERT_TRUE(OverviewController::Get()->InOverviewSession());
ClickOnDeskNameViewAtIndex(0);
PressAndReleaseKey(ui::VKEY_A, ui::EF_CONTROL_DOWN);
PressAndReleaseKey(ui::VKEY_BACK);
PressAndReleaseKey(ui::VKEY_RETURN);
auto* desk_1 = controller()->GetDeskAtIndex(0);
EXPECT_FALSE(desk_1->name().empty());
EXPECT_FALSE(desk_1->is_name_set_by_user());
EXPECT_EQ(u"Desk 1", desk_1->name());
EXPECT_THAT(GetDeskRestoreNames(GetPrimaryUserPrefService()),
ElementsAre("", ""));
}
TEST_P(DesksEditableNamesTest, RevertDeskNameOnEscape) {
ASSERT_EQ(2u, controller()->desks().size());
ASSERT_TRUE(OverviewController::Get()->InOverviewSession());
ClickOnDeskNameViewAtIndex(0);
PressAndReleaseKey(ui::VKEY_E);
PressAndReleaseKey(ui::VKEY_S);
PressAndReleaseKey(ui::VKEY_C);
PressAndReleaseKey(ui::VKEY_ESCAPE);
auto* desk_1 = controller()->GetDeskAtIndex(0);
EXPECT_FALSE(desk_1->is_name_set_by_user());
EXPECT_EQ(u"Desk 1", desk_1->name());
}
TEST_P(DesksEditableNamesTest, SelectAllOnFocus) {
ASSERT_EQ(2u, controller()->desks().size());
ASSERT_TRUE(OverviewController::Get()->InOverviewSession());
ClickOnDeskNameViewAtIndex(0);
auto* desk_name_view = desks_bar_view()->mini_views()[0]->desk_name_view();
EXPECT_TRUE(desk_name_view->HasFocus());
EXPECT_TRUE(desk_name_view->HasSelection());
auto* desk_1 = controller()->GetDeskAtIndex(0);
EXPECT_EQ(desk_1->name(), desk_name_view->GetSelectedText());
}
TEST_P(DesksEditableNamesTest, EventsThatCommitChanges) {
ASSERT_EQ(2u, controller()->desks().size());
ASSERT_TRUE(OverviewController::Get()->InOverviewSession());
ClickOnDeskNameViewAtIndex(0);
auto* desk_name_view = desks_bar_view()->mini_views()[0]->desk_name_view();
EXPECT_TRUE(desk_name_view->HasFocus());
auto* new_desk_button = desks_bar_view()->new_desk_button();
LeftClickOn(new_desk_button);
RunScheduledLayoutForAllOverviewDeskBars();
ASSERT_EQ(3u, controller()->desks().size());
EXPECT_FALSE(desk_name_view->HasFocus());
ClickOnDeskNameViewAtIndex(0);
RunScheduledLayoutForAllOverviewDeskBars();
EXPECT_TRUE(desk_name_view->HasFocus());
auto* event_generator = GetEventGenerator();
CloseDeskFromMiniView(desks_bar_view()->mini_views()[2], event_generator);
RunScheduledLayoutForAllOverviewDeskBars();
ASSERT_EQ(2u, controller()->desks().size());
EXPECT_FALSE(desk_name_view->HasFocus());
ClickOnDeskNameViewAtIndex(0);
RunScheduledLayoutForAllOverviewDeskBars();
EXPECT_TRUE(desk_name_view->HasFocus());
event_generator->MoveMouseTo(gfx::Point(2, 2));
event_generator->ClickLeftButton();
EXPECT_FALSE(desk_name_view->HasFocus());
ASSERT_TRUE(OverviewController::Get()->InOverviewSession());
}
TEST_P(DesksEditableNamesTest, MaxLength) {
ASSERT_EQ(2u, controller()->desks().size());
ASSERT_TRUE(OverviewController::Get()->InOverviewSession());
ClickOnDeskNameViewAtIndex(0);
PressAndReleaseKey(ui::VKEY_A, ui::EF_CONTROL_DOWN);
PressAndReleaseKey(ui::VKEY_BACK);
std::u16string expected_desk_name(DeskTextfield::kMaxLength, L'a');
for (size_t i = 0; i < DeskTextfield::kMaxLength + 10; ++i) {
PressAndReleaseKey(ui::VKEY_A);
}
PressAndReleaseKey(ui::VKEY_RETURN);
auto* desk_1 = controller()->GetDeskAtIndex(0);
EXPECT_EQ(DeskTextfield::kMaxLength, desk_1->name().size());
EXPECT_EQ(expected_desk_name, desk_1->name());
EXPECT_TRUE(desk_1->is_name_set_by_user());
std::u16string clipboard_text(DeskTextfield::kMaxLength + 10, L'b');
expected_desk_name = std::u16string(DeskTextfield::kMaxLength, L'b');
EXPECT_GT(clipboard_text.size(), DeskTextfield::kMaxLength);
ui::ScopedClipboardWriter(ui::ClipboardBuffer::kCopyPaste)
.WriteText(clipboard_text);
ClickOnDeskNameViewAtIndex(0);
PressAndReleaseKey(ui::VKEY_A, ui::EF_CONTROL_DOWN);
PressAndReleaseKey(ui::VKEY_BACK);
PressAndReleaseKey(ui::VKEY_V, ui::EF_CONTROL_DOWN);
PressAndReleaseKey(ui::VKEY_RETURN);
EXPECT_EQ(DeskTextfield::kMaxLength, desk_1->name().size());
EXPECT_EQ(expected_desk_name, desk_1->name());
}
class TabletModeDesksTest : public DesksTest {
public:
TabletModeDesksTest() = default;
TabletModeDesksTest(const TabletModeDesksTest&) = delete;
TabletModeDesksTest& operator=(const TabletModeDesksTest&) = delete;
~TabletModeDesksTest() override = default;
void SetUp() override {
DesksTest::SetUp();
TabletModeControllerTestApi tablet_mode_test_api;
tablet_mode_test_api.DetachAllMice();
tablet_mode_test_api.EnterTabletMode();
}
SplitViewController* split_view_controller() {
return SplitViewController::Get(Shell::GetPrimaryRootWindow());
}
};
class WindowVisibilityObserver : public aura::WindowObserver {
public:
WindowVisibilityObserver(aura::Window* window, base::OnceClosure callback)
: on_visibility_changed_callback_(std::move(callback)) {
DCHECK(on_visibility_changed_callback_);
observer_.Observe(window);
}
WindowVisibilityObserver(const WindowVisibilityObserver&) = delete;
WindowVisibilityObserver& operator=(const WindowVisibilityObserver&) = delete;
~WindowVisibilityObserver() override = default;
void OnWindowVisibilityChanged(aura::Window* window, bool visible) override {
if (observer_.IsObservingSource(window) &&
on_visibility_changed_callback_) {
std::move(on_visibility_changed_callback_).Run();
}
}
void OnWindowDestroying(aura::Window* window) override {
DCHECK(observer_.IsObservingSource(window));
observer_.Reset();
}
private:
base::ScopedObservation<aura::Window, aura::WindowObserver> observer_{this};
base::OnceClosure on_visibility_changed_callback_;
};
TEST_P(TabletModeDesksTest, CantDestroyBackdropWhileHiding) {
auto* controller = DesksController::Get();
ASSERT_EQ(1u, controller->desks().size());
const Desk* desk_1 = controller->GetDeskAtIndex(0);
auto window = CreateAppWindow(gfx::Rect(0, 0, 250, 100));
wm::ActivateWindow(window.get());
EXPECT_EQ(window.get(), window_util::GetActiveWindow());
auto* desk_1_backdrop_controller =
GetDeskBackdropController(desk_1, Shell::GetPrimaryRootWindow());
auto* backdrop_window = desk_1_backdrop_controller->backdrop_window();
ASSERT_TRUE(backdrop_window);
EXPECT_TRUE(backdrop_window->IsVisible());
auto* app_window = window.get();
WindowVisibilityObserver observer{
backdrop_window,
base::BindLambdaForTesting([app_window, backdrop_window]() {
app_window->Hide();
EXPECT_FALSE(backdrop_window->IsVisible());
})};
EnterOverview();
EXPECT_TRUE(OverviewController::Get()->InOverviewSession());
ASSERT_TRUE(desk_1_backdrop_controller->backdrop_window());
EXPECT_FALSE(desk_1_backdrop_controller->backdrop_window()->IsVisible());
}
TEST_P(TabletModeDesksTest, Backdrops) {
auto* controller = DesksController::Get();
NewDesk();
ASSERT_EQ(2u, controller->desks().size());
const Desk* desk_1 = controller->GetDeskAtIndex(0);
const Desk* desk_2 = controller->GetDeskAtIndex(1);
auto window = CreateAppWindow(gfx::Rect(0, 0, 250, 100));
wm::ActivateWindow(window.get());
EXPECT_EQ(window.get(), window_util::GetActiveWindow());
auto* desk_1_backdrop_controller =
GetDeskBackdropController(desk_1, Shell::GetPrimaryRootWindow());
auto* desk_2_backdrop_controller =
GetDeskBackdropController(desk_2, Shell::GetPrimaryRootWindow());
ASSERT_TRUE(desk_1_backdrop_controller->backdrop_window());
EXPECT_TRUE(desk_1_backdrop_controller->backdrop_window()->IsVisible());
EXPECT_FALSE(desk_2_backdrop_controller->backdrop_window());
auto* overview_controller = OverviewController::Get();
EnterOverview();
EXPECT_TRUE(overview_controller->InOverviewSession());
ASSERT_TRUE(desk_1_backdrop_controller->backdrop_window());
EXPECT_FALSE(desk_1_backdrop_controller->backdrop_window()->IsVisible());
auto* overview_grid = GetOverviewGridForRoot(Shell::GetPrimaryRootWindow());
EXPECT_EQ(1u, overview_grid->GetNumWindows());
auto* overview_session = overview_controller->overview_session();
auto* overview_item =
overview_session->GetOverviewItemForWindow(window.get());
ASSERT_TRUE(overview_item);
const auto* desks_bar_view = overview_grid->desks_bar_view();
ASSERT_TRUE(desks_bar_view);
auto* desk_2_mini_view = desks_bar_view->mini_views()[1].get();
EXPECT_EQ(desk_2, desk_2_mini_view->desk());
DragItemToPoint(overview_item,
desk_2_mini_view->GetBoundsInScreen().CenterPoint(),
GetEventGenerator());
EXPECT_TRUE(overview_controller->InOverviewSession());
EXPECT_TRUE(base::Contains(desk_2->windows(), window.get()));
EXPECT_FALSE(desk_1_backdrop_controller->backdrop_window());
ASSERT_TRUE(desk_2_backdrop_controller->backdrop_window());
EXPECT_FALSE(desk_2_backdrop_controller->backdrop_window()->IsVisible());
ExitOverview(OverviewEnterExitType::kImmediateExit);
EXPECT_FALSE(overview_controller->InOverviewSession());
EXPECT_FALSE(desk_1_backdrop_controller->backdrop_window());
ASSERT_TRUE(desk_2_backdrop_controller->backdrop_window());
EXPECT_FALSE(desk_2_backdrop_controller->backdrop_window()->IsVisible());
ActivateDesk(desk_2);
EXPECT_FALSE(desk_1_backdrop_controller->backdrop_window());
ASSERT_TRUE(desk_2_backdrop_controller->backdrop_window());
EXPECT_TRUE(desk_2_backdrop_controller->backdrop_window()->IsVisible());
TabletModeControllerTestApi().LeaveTabletMode();
EXPECT_FALSE(desk_1_backdrop_controller->backdrop_window());
EXPECT_FALSE(desk_2_backdrop_controller->backdrop_window());
}
TEST_P(TabletModeDesksTest,
BackdropStackingAndMiniviewsUpdatesWithOverviewDragDrop) {
auto* controller = DesksController::Get();
NewDesk();
ASSERT_EQ(2u, controller->desks().size());
Desk* desk_1 = controller->GetDeskAtIndex(0);
Desk* desk_2 = controller->GetDeskAtIndex(1);
auto window = CreateAppWindow(gfx::Rect(0, 0, 250, 100));
wm::ActivateWindow(window.get());
EXPECT_EQ(window.get(), window_util::GetActiveWindow());
auto* desk_1_backdrop_controller =
GetDeskBackdropController(desk_1, Shell::GetPrimaryRootWindow());
auto* desk_2_backdrop_controller =
GetDeskBackdropController(desk_2, Shell::GetPrimaryRootWindow());
auto* overview_controller = OverviewController::Get();
EnterOverview();
EXPECT_TRUE(overview_controller->InOverviewSession());
ASSERT_TRUE(desk_1_backdrop_controller->backdrop_window());
EXPECT_FALSE(desk_2_backdrop_controller->backdrop_window());
EXPECT_EQ(window.get(), desk_1_backdrop_controller->window_having_backdrop());
EXPECT_FALSE(desk_2_backdrop_controller->window_having_backdrop());
EXPECT_TRUE(window_util::IsStackedBelow(
desk_1_backdrop_controller->backdrop_window(), window.get()));
auto* overview_grid = GetOverviewGridForRoot(Shell::GetPrimaryRootWindow());
EXPECT_EQ(1u, overview_grid->GetNumWindows());
auto* overview_session = overview_controller->overview_session();
auto* overview_item =
overview_session->GetOverviewItemForWindow(window.get());
ASSERT_TRUE(overview_item);
const auto* desks_bar_view = overview_grid->desks_bar_view();
ASSERT_TRUE(desks_bar_view);
auto* desk_2_mini_view = desks_bar_view->mini_views()[1].get();
TestDeskObserver observer1;
TestDeskObserver observer2;
desk_1->AddObserver(&observer1);
desk_2->AddObserver(&observer2);
{
gfx::ScopedAnimationDurationScaleMode normal_anim(
gfx::ScopedAnimationDurationScaleMode::NORMAL_DURATION);
DragItemToPoint(overview_item,
desk_2_mini_view->GetBoundsInScreen().CenterPoint(),
GetEventGenerator());
}
EXPECT_TRUE(overview_controller->InOverviewSession());
EXPECT_TRUE(base::Contains(desk_2->windows(), window.get()));
EXPECT_FALSE(desk_1_backdrop_controller->backdrop_window());
ASSERT_TRUE(desk_2_backdrop_controller->backdrop_window());
EXPECT_FALSE(desk_1_backdrop_controller->window_having_backdrop());
EXPECT_EQ(window.get(), desk_2_backdrop_controller->window_having_backdrop());
EXPECT_TRUE(window_util::IsStackedBelow(
desk_2_backdrop_controller->backdrop_window(), window.get()));
EXPECT_EQ(1, observer1.notify_counts());
EXPECT_EQ(1, observer2.notify_counts());
desk_1->RemoveObserver(&observer1);
desk_2->RemoveObserver(&observer2);
}
TEST_P(TabletModeDesksTest, NoDesksBarInTabletModeWithOneDesk) {
auto* controller = DesksController::Get();
ASSERT_EQ(1u, controller->desks().size());
auto window = CreateAppWindow(gfx::Rect(0, 0, 250, 100));
wm::ActivateWindow(window.get());
EXPECT_EQ(window.get(), window_util::GetActiveWindow());
auto* overview_controller = OverviewController::Get();
EnterOverview();
EXPECT_TRUE(overview_controller->InOverviewSession());
const auto* overview_grid =
GetOverviewGridForRoot(Shell::GetPrimaryRootWindow());
const auto* desks_bar_view = overview_grid->desks_bar_view();
ASSERT_FALSE(desks_bar_view);
auto* overview_session = overview_controller->overview_session();
auto* overview_item =
overview_session->GetOverviewItemForWindow(window.get());
DragItemToPoint(overview_item, window->GetBoundsInScreen().CenterPoint(),
GetEventGenerator(), true);
ExitOverview();
EXPECT_FALSE(overview_controller->InOverviewSession());
NewDesk();
EnterOverview();
EXPECT_TRUE(overview_controller->InOverviewSession());
overview_grid = GetOverviewGridForRoot(Shell::GetPrimaryRootWindow());
desks_bar_view = overview_grid->desks_bar_view();
ASSERT_TRUE(desks_bar_view);
ASSERT_EQ(2u, desks_bar_view->mini_views().size());
}
TEST_P(TabletModeDesksTest, DesksCreationRemovalCycle) {
auto window = CreateAppWindow(gfx::Rect(0, 0, 250, 100));
wm::ActivateWindow(window.get());
EXPECT_EQ(window.get(), window_util::GetActiveWindow());
auto* desks_controller = DesksController::Get();
for (size_t i = 0; i < 2 * desks_util::GetMaxNumberOfDesks(); ++i) {
NewDesk();
ASSERT_EQ(2u, desks_controller->desks().size());
const Desk* desk_1 = desks_controller->GetDeskAtIndex(0);
const Desk* desk_2 = desks_controller->GetDeskAtIndex(1);
auto* desk_1_backdrop_controller =
GetDeskBackdropController(desk_1, Shell::GetPrimaryRootWindow());
auto* desk_2_backdrop_controller =
GetDeskBackdropController(desk_2, Shell::GetPrimaryRootWindow());
{
SCOPED_TRACE("Check backdrops after desk creation");
ASSERT_TRUE(desk_1_backdrop_controller->backdrop_window());
EXPECT_TRUE(desk_1_backdrop_controller->backdrop_window()->IsVisible());
EXPECT_FALSE(desk_2_backdrop_controller->backdrop_window());
}
RemoveDesk(desk_1);
{
SCOPED_TRACE("Check backdrops after desk removal");
EXPECT_TRUE(desk_2->is_active());
EXPECT_TRUE(DoesActiveDeskContainWindow(window.get()));
EXPECT_FALSE(desk_1_backdrop_controller->backdrop_window());
ASSERT_TRUE(desk_2_backdrop_controller->backdrop_window());
EXPECT_TRUE(desk_2_backdrop_controller->backdrop_window()->IsVisible());
}
}
}
TEST_P(TabletModeDesksTest, RestoreSplitViewOnDeskSwitch) {
auto* desks_controller = DesksController::Get();
NewDesk();
ASSERT_EQ(2u, desks_controller->desks().size());
Desk* desk_1 = desks_controller->GetDeskAtIndex(0);
Desk* desk_2 = desks_controller->GetDeskAtIndex(1);
auto win1 = CreateAppWindow(gfx::Rect(0, 0, 250, 100));
auto win2 = CreateAppWindow(gfx::Rect(0, 0, 250, 100));
split_view_controller()->SnapWindow(win1.get(), SnapPosition::kPrimary);
split_view_controller()->SnapWindow(win2.get(), SnapPosition::kSecondary);
EXPECT_EQ(win1.get(), split_view_controller()->primary_window());
EXPECT_EQ(win2.get(), split_view_controller()->secondary_window());
ActivateDesk(desk_2);
EXPECT_EQ(nullptr, split_view_controller()->primary_window());
EXPECT_EQ(nullptr, split_view_controller()->secondary_window());
EXPECT_TRUE(WindowState::Get(win1.get())->IsSnapped());
EXPECT_TRUE(WindowState::Get(win2.get())->IsSnapped());
auto win3 = CreateAppWindow(gfx::Rect(0, 0, 250, 100));
auto win4 = CreateAppWindow(gfx::Rect(0, 0, 250, 100));
split_view_controller()->SnapWindow(win3.get(), SnapPosition::kPrimary);
split_view_controller()->SnapWindow(win4.get(), SnapPosition::kSecondary);
EXPECT_EQ(win3.get(), split_view_controller()->primary_window());
EXPECT_EQ(win4.get(), split_view_controller()->secondary_window());
ActivateDesk(desk_1);
EXPECT_EQ(win1.get(), split_view_controller()->primary_window());
EXPECT_EQ(win2.get(), split_view_controller()->secondary_window());
EXPECT_TRUE(WindowState::Get(win3.get())->IsSnapped());
EXPECT_TRUE(WindowState::Get(win4.get())->IsSnapped());
}
TEST_P(
TabletModeDesksTest,
SnappedStateRetainedOnSwitchingDesksWithOverviewFullOfUnsnappableWindows) {
auto* desks_controller = DesksController::Get();
NewDesk();
ASSERT_EQ(2u, desks_controller->desks().size());
const gfx::Rect work_area =
screen_util::GetDisplayWorkAreaBoundsInScreenForActiveDeskContainer(
Shell::GetPrimaryRootWindow());
const gfx::Size big(work_area.width() * 2 / 3, work_area.height() * 2 / 3);
const gfx::Size small(250, 100);
std::unique_ptr<aura::Window> win1 = CreateTestWindow(gfx::Rect(small));
aura::test::TestWindowDelegate win2_delegate;
win2_delegate.set_minimum_size(big);
std::unique_ptr<aura::Window> win2(CreateTestWindowInShell(
{.delegate = &win2_delegate, .bounds = gfx::Rect(big)}));
aura::test::TestWindowDelegate win3_delegate;
win3_delegate.set_minimum_size(big);
std::unique_ptr<aura::Window> win3(CreateTestWindowInShell(
{.delegate = &win3_delegate, .bounds = gfx::Rect(big)}));
ASSERT_TRUE(EnterOverview());
split_view_controller()->SnapWindow(win1.get(), SnapPosition::kPrimary);
EXPECT_EQ(win1.get(), split_view_controller()->primary_window());
EXPECT_FALSE(split_view_controller()->CanSnapWindow(
win2.get(), chromeos::kDefaultSnapRatio));
EXPECT_FALSE(split_view_controller()->CanSnapWindow(
win3.get(), chromeos::kDefaultSnapRatio));
PressAndReleaseKey(ui::VKEY_OEM_6, ui::EF_COMMAND_DOWN);
DeskSwitchAnimationWaiter().Wait();
EXPECT_TRUE(WindowState::Get(win1.get())->IsSnapped());
EXPECT_EQ(SplitViewController::State::kNoSnap,
split_view_controller()->state());
ASSERT_TRUE(OverviewController::Get()->InOverviewSession());
PressAndReleaseKey(ui::VKEY_OEM_4, ui::EF_COMMAND_DOWN);
DeskSwitchAnimationWaiter().Wait();
EXPECT_TRUE(WindowState::Get(win1.get())->IsSnapped());
EXPECT_EQ(SplitViewController::State::kPrimarySnapped,
split_view_controller()->state());
EXPECT_EQ(win1.get(), split_view_controller()->primary_window());
}
TEST_P(TabletModeDesksTest, OverviewStateOnSwitchToDeskWithSplitView) {
auto* desks_controller = DesksController::Get();
NewDesk();
ASSERT_EQ(2u, desks_controller->desks().size());
Desk* desk_1 = desks_controller->GetDeskAtIndex(0);
Desk* desk_2 = desks_controller->GetDeskAtIndex(1);
auto win1 = CreateAppWindow(gfx::Rect(0, 0, 250, 100));
auto win2 = CreateAppWindow(gfx::Rect(0, 0, 250, 100));
split_view_controller()->SnapWindow(win1.get(), SnapPosition::kPrimary);
split_view_controller()->SnapWindow(win2.get(), SnapPosition::kSecondary);
EXPECT_EQ(win1.get(), split_view_controller()->primary_window());
EXPECT_EQ(win2.get(), split_view_controller()->secondary_window());
auto* overview_controller = OverviewController::Get();
EXPECT_FALSE(overview_controller->InOverviewSession());
ActivateDesk(desk_2);
EXPECT_FALSE(overview_controller->InOverviewSession());
auto win3 = CreateAppWindow(gfx::Rect(0, 0, 250, 100));
split_view_controller()->SnapWindow(win3.get(), SnapPosition::kPrimary);
EXPECT_EQ(win3.get(), split_view_controller()->primary_window());
EXPECT_EQ(nullptr, split_view_controller()->secondary_window());
ActivateDesk(desk_1);
EXPECT_FALSE(overview_controller->InOverviewSession());
ActivateDesk(desk_2);
EXPECT_TRUE(overview_controller->InOverviewSession());
ActivateDesk(desk_1);
EXPECT_FALSE(overview_controller->InOverviewSession());
}
TEST_P(TabletModeDesksTest, RemovingDesksWithSplitView) {
auto* desks_controller = DesksController::Get();
NewDesk();
ASSERT_EQ(2u, desks_controller->desks().size());
Desk* desk_2 = desks_controller->GetDeskAtIndex(1);
auto win1 = CreateAppWindow(gfx::Rect(0, 0, 250, 100));
split_view_controller()->SnapWindow(win1.get(), SnapPosition::kPrimary);
EXPECT_EQ(win1.get(), split_view_controller()->primary_window());
EXPECT_EQ(nullptr, split_view_controller()->secondary_window());
ActivateDesk(desk_2);
auto win2 = CreateAppWindow(gfx::Rect(0, 0, 250, 100));
split_view_controller()->SnapWindow(win2.get(), SnapPosition::kSecondary);
EXPECT_EQ(nullptr, split_view_controller()->primary_window());
EXPECT_EQ(win2.get(), split_view_controller()->secondary_window());
RemoveDesk(desk_2);
EXPECT_EQ(win1.get(), split_view_controller()->primary_window());
EXPECT_EQ(win2.get(), split_view_controller()->secondary_window());
EXPECT_EQ(SplitViewController::State::kBothSnapped,
split_view_controller()->state());
}
TEST_P(TabletModeDesksTest, RemoveDeskWithMaximizedWindowAndMergeWithSnapped) {
auto* desks_controller = DesksController::Get();
NewDesk();
ASSERT_EQ(2u, desks_controller->desks().size());
Desk* desk_2 = desks_controller->GetDeskAtIndex(1);
auto win1 = CreateAppWindow(gfx::Rect(0, 0, 250, 100));
split_view_controller()->SnapWindow(win1.get(), SnapPosition::kPrimary);
EXPECT_EQ(win1.get(), split_view_controller()->primary_window());
EXPECT_EQ(nullptr, split_view_controller()->secondary_window());
ActivateDesk(desk_2);
auto win2 = CreateAppWindow(gfx::Rect(0, 0, 250, 100));
EXPECT_EQ(nullptr, split_view_controller()->primary_window());
EXPECT_EQ(nullptr, split_view_controller()->secondary_window());
EXPECT_TRUE(WindowState::Get(win2.get())->IsMaximized());
RemoveDesk(desk_2);
EXPECT_TRUE(OverviewController::Get()->InOverviewSession());
EXPECT_EQ(win1.get(), split_view_controller()->primary_window());
EXPECT_EQ(nullptr, split_view_controller()->secondary_window());
EXPECT_EQ(SplitViewController::State::kPrimarySnapped,
split_view_controller()->state());
}
TEST_P(TabletModeDesksTest, RemovingActiveDeskDoesNotExitOverview) {
auto* desks_controller = DesksController::Get();
NewDesk();
ASSERT_EQ(2u, desks_controller->desks().size());
Desk* desk_2 = desks_controller->GetDeskAtIndex(1);
ActivateDesk(desk_2);
auto* overview_controller = OverviewController::Get();
EnterOverview();
ASSERT_TRUE(overview_controller->InOverviewSession());
RemoveDesk(desk_2);
EXPECT_TRUE(overview_controller->InOverviewSession());
}
TEST_P(TabletModeDesksTest, BackdropsStacking) {
auto* desks_controller = DesksController::Get();
NewDesk();
ASSERT_EQ(2u, desks_controller->desks().size());
Desk* desk_1 = desks_controller->GetDeskAtIndex(0);
Desk* desk_2 = desks_controller->GetDeskAtIndex(1);
auto win1 = CreateAppWindow(gfx::Rect(0, 0, 250, 100));
auto win2 = CreateAppWindow(gfx::Rect(0, 0, 250, 100));
split_view_controller()->SnapWindow(win1.get(), SnapPosition::kPrimary);
split_view_controller()->SnapWindow(win2.get(), SnapPosition::kSecondary);
auto* desk_1_backdrop_controller =
GetDeskBackdropController(desk_1, Shell::GetPrimaryRootWindow());
auto* desk_2_backdrop_controller =
GetDeskBackdropController(desk_2, Shell::GetPrimaryRootWindow());
ASSERT_TRUE(desk_1_backdrop_controller->backdrop_window());
EXPECT_FALSE(desk_2_backdrop_controller->backdrop_window());
auto* desk_1_backdrop = desk_1_backdrop_controller->backdrop_window();
EXPECT_TRUE(window_util::IsStackedBelow(desk_1_backdrop, win1.get()));
EXPECT_TRUE(window_util::IsStackedBelow(desk_1_backdrop, win2.get()));
ActivateDesk(desk_2);
ASSERT_TRUE(desk_1_backdrop_controller->backdrop_window());
EXPECT_FALSE(desk_2_backdrop_controller->backdrop_window());
EXPECT_TRUE(window_util::IsStackedBelow(desk_1_backdrop, win1.get()));
EXPECT_TRUE(window_util::IsStackedBelow(desk_1_backdrop, win2.get()));
auto win3 = CreateAppWindow(gfx::Rect(0, 0, 250, 100));
auto win4 = CreateAppWindow(gfx::Rect(0, 0, 250, 100));
split_view_controller()->SnapWindow(win3.get(), SnapPosition::kPrimary);
split_view_controller()->SnapWindow(win4.get(), SnapPosition::kSecondary);
ASSERT_TRUE(desk_1_backdrop_controller->backdrop_window());
ASSERT_TRUE(desk_2_backdrop_controller->backdrop_window());
auto* desk_2_backdrop = desk_2_backdrop_controller->backdrop_window();
EXPECT_TRUE(window_util::IsStackedBelow(desk_2_backdrop, win3.get()));
EXPECT_TRUE(window_util::IsStackedBelow(desk_2_backdrop, win4.get()));
}
TEST_P(TabletModeDesksTest, RestoringUnsnappableWindowsInSplitView) {
UpdateDisplay("600x400");
display::test::DisplayManagerTestApi(display_manager())
.SetFirstDisplayAsInternalDisplay();
auto window = CreateAppWindow(gfx::Rect(350, 350));
views::Widget* widget = views::Widget::GetWidgetForNativeWindow(window.get());
widget->widget_delegate()->GetContentsView()->SetPreferredSize(
gfx::Size(350, 100));
EXPECT_FALSE(split_view_controller()->CanSnapWindow(
window.get(), chromeos::kDefaultSnapRatio));
ScreenOrientationControllerTestApi test_api(
Shell::Get()->screen_orientation_controller());
test_api.SetDisplayRotation(display::Display::ROTATE_270,
display::Display::RotationSource::ACTIVE);
EXPECT_EQ(test_api.GetCurrentOrientation(),
chromeos::OrientationType::kPortraitPrimary);
EXPECT_TRUE(split_view_controller()->CanSnapWindow(
window.get(), chromeos::kDefaultSnapRatio));
split_view_controller()->SnapWindow(window.get(), SnapPosition::kPrimary);
EXPECT_EQ(window.get(), split_view_controller()->primary_window());
EXPECT_TRUE(split_view_controller()->InSplitViewMode());
auto* controller = DesksController::Get();
NewDesk();
ASSERT_EQ(2u, controller->desks().size());
const Desk* desk_2 = controller->GetDeskAtIndex(1);
ActivateDesk(desk_2);
EXPECT_EQ(desk_2, controller->active_desk());
test_api.SetDisplayRotation(display::Display::ROTATE_0,
display::Display::RotationSource::ACTIVE);
EXPECT_EQ(test_api.GetCurrentOrientation(),
chromeos::OrientationType::kLandscapePrimary);
const Desk* desk_1 = controller->GetDeskAtIndex(0);
ActivateDesk(desk_1);
EXPECT_EQ(desk_1, controller->active_desk());
EXPECT_FALSE(split_view_controller()->InSplitViewMode());
EXPECT_TRUE(WindowState::Get(window.get())->IsMaximized());
}
TEST_P(DesksTest, MiniViewsTouchGestures) {
auto* controller = DesksController::Get();
NewDesk();
NewDesk();
ASSERT_EQ(3u, controller->desks().size());
auto* overview_controller = OverviewController::Get();
EnterOverview();
EXPECT_TRUE(overview_controller->InOverviewSession());
const auto* overview_grid =
GetOverviewGridForRoot(Shell::GetPrimaryRootWindow());
const auto* desks_bar_view = overview_grid->desks_bar_view();
ASSERT_TRUE(desks_bar_view);
ASSERT_EQ(3u, desks_bar_view->mini_views().size());
auto* desk_1_mini_view = desks_bar_view->mini_views()[0].get();
auto* desk_2_mini_view = desks_bar_view->mini_views()[1].get();
auto* desk_3_mini_view = desks_bar_view->mini_views()[2].get();
auto* event_generator = GetEventGenerator();
const gfx::Point desk_1_preview_center =
desk_1_mini_view->desk_preview()->GetBoundsInScreen().CenterPoint();
const gfx::Point desk_2_preview_center =
desk_2_mini_view->desk_preview()->GetBoundsInScreen().CenterPoint();
LongGestureTap(desk_1_preview_center, event_generator);
event_generator->GestureTapDownAndUp(desk_1_preview_center);
base::RunLoop().RunUntilIdle();
EXPECT_TRUE(GetDeskActionVisibilityForMiniView(desk_1_mini_view));
EXPECT_FALSE(GetDeskActionVisibilityForMiniView(desk_2_mini_view));
EXPECT_FALSE(GetDeskActionVisibilityForMiniView(desk_3_mini_view));
LongGestureTap(desk_2_preview_center, event_generator);
event_generator->GestureTapDownAndUp(desk_2_preview_center);
base::RunLoop().RunUntilIdle();
EXPECT_FALSE(GetDeskActionVisibilityForMiniView(desk_1_mini_view));
EXPECT_TRUE(GetDeskActionVisibilityForMiniView(desk_2_mini_view));
EXPECT_FALSE(GetDeskActionVisibilityForMiniView(desk_3_mini_view));
GestureTapOn(GetCloseDeskButtonForMiniView(desk_2_mini_view));
ASSERT_EQ(2u, controller->desks().size());
ASSERT_EQ(2u, desks_bar_view->mini_views().size());
EXPECT_TRUE(overview_controller->InOverviewSession());
EXPECT_FALSE(GetDeskActionVisibilityForMiniView(desk_1_mini_view));
GestureTapOn(GetCloseDeskButtonForMiniView(desk_1_mini_view));
ASSERT_EQ(2u, controller->desks().size());
EXPECT_FALSE(overview_controller->InOverviewSession());
EXPECT_TRUE(controller->GetDeskAtIndex(0)->is_active());
}
TEST_P(DesksTest, AutohiddenShelfAnimatesAfterDeskSwitch) {
Shelf* shelf = GetPrimaryShelf();
ShelfWidget* shelf_widget = shelf->shelf_widget();
const gfx::Rect shown_shelf_bounds = shelf_widget->GetWindowBoundsInScreen();
shelf->SetAutoHideBehavior(ShelfAutoHideBehavior::kAlways);
gfx::ScopedAnimationDurationScaleMode non_zero_animation(
gfx::ScopedAnimationDurationScaleMode::NON_ZERO_DURATION);
NewDesk();
std::unique_ptr<views::Widget> widget =
CreateTestWidget(views::Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET);
widget->Maximize();
shelf->shelf_layout_manager()->LayoutShelf();
EXPECT_EQ(SHELF_AUTO_HIDE, shelf->GetVisibilityState());
EXPECT_EQ(SHELF_AUTO_HIDE_HIDDEN, shelf->GetAutoHideState());
const gfx::Rect hidden_shelf_bounds = shelf_widget->GetWindowBoundsInScreen();
EXPECT_NE(shown_shelf_bounds, hidden_shelf_bounds);
ActivateDesk(DesksController::Get()->GetDeskAtIndex(1));
EXPECT_EQ(SHELF_AUTO_HIDE_SHOWN, shelf->GetAutoHideState());
gfx::Rect transformed_bounds = shelf_widget->GetLayer()->transform().MapRect(
shelf_widget->GetWindowBoundsInScreen());
EXPECT_EQ(transformed_bounds, hidden_shelf_bounds);
EXPECT_EQ(shelf_widget->GetWindowBoundsInScreen(), shown_shelf_bounds);
ui::LayerAnimationStoppedWaiter().Wait(shelf_widget->GetLayer());
EXPECT_EQ(SHELF_AUTO_HIDE_SHOWN, shelf->GetAutoHideState());
}
TEST_P(DesksTest, SwitchToDeskWithSnappedActiveWindow) {
auto* desks_controller = DesksController::Get();
auto* overview_controller = OverviewController::Get();
NewDesk();
ASSERT_EQ(2u, desks_controller->desks().size());
Desk* desk_1 = desks_controller->GetDeskAtIndex(0);
Desk* desk_2 = desks_controller->GetDeskAtIndex(1);
auto win0 = CreateAppWindow(gfx::Rect(0, 0, 250, 100));
auto win1 = CreateAppWindow(gfx::Rect(50, 50, 200, 200));
WindowState* win0_state = WindowState::Get(win0.get());
WindowSnapWMEvent snap_to_left(WM_EVENT_CYCLE_SNAP_PRIMARY);
win0_state->OnWMEvent(&snap_to_left);
EXPECT_EQ(chromeos::WindowStateType::kPrimarySnapped,
win0_state->GetStateType());
auto* split_view_controller =
SplitViewController::Get(Shell::GetPrimaryRootWindow());
EXPECT_FALSE(split_view_controller->InSplitViewMode());
EXPECT_FALSE(overview_controller->InOverviewSession());
ActivateDesk(desk_2);
EXPECT_FALSE(split_view_controller->InSplitViewMode());
EXPECT_FALSE(overview_controller->InOverviewSession());
ActivateDesk(desk_1);
EXPECT_FALSE(split_view_controller->InSplitViewMode());
EXPECT_FALSE(overview_controller->InOverviewSession());
}
TEST_P(DesksTest, SuccessfulDragToDeskRemovesSplitViewIndicators) {
auto* controller = DesksController::Get();
NewDesk();
ASSERT_EQ(2u, controller->desks().size());
auto window = CreateAppWindow(gfx::Rect(0, 0, 250, 100));
wm::ActivateWindow(window.get());
EXPECT_EQ(window.get(), window_util::GetActiveWindow());
auto* overview_controller = OverviewController::Get();
EnterOverview();
EXPECT_TRUE(overview_controller->InOverviewSession());
auto* overview_grid = GetOverviewGridForRoot(Shell::GetPrimaryRootWindow());
auto* overview_session = overview_controller->overview_session();
auto* overview_item =
overview_session->GetOverviewItemForWindow(window.get());
ASSERT_TRUE(overview_item);
const auto* desks_bar_view = overview_grid->desks_bar_view();
ASSERT_TRUE(desks_bar_view);
ASSERT_EQ(2u, desks_bar_view->mini_views().size());
auto* desk_2_mini_view = desks_bar_view->mini_views()[1].get();
DragItemToPoint(overview_item,
desk_2_mini_view->GetBoundsInScreen().CenterPoint(),
GetEventGenerator(),
false,
false);
EXPECT_TRUE(overview_grid->drop_target());
EXPECT_EQ(SplitViewDragIndicators::WindowDraggingState::kFromOverview,
overview_session->grid_list()[0]
->split_view_drag_indicators()
->current_window_dragging_state());
GetEventGenerator()->ReleaseLeftButton();
EXPECT_TRUE(overview_controller->InOverviewSession());
EXPECT_TRUE(overview_grid->empty());
EXPECT_FALSE(DoesActiveDeskContainWindow(window.get()));
EXPECT_TRUE(overview_grid->no_windows_widget());
EXPECT_FALSE(overview_grid->drop_target());
EXPECT_EQ(SplitViewDragIndicators::WindowDraggingState::kNoDrag,
overview_session->grid_list()[0]
->split_view_drag_indicators()
->current_window_dragging_state());
}
TEST_P(DesksTest, DragAllOverviewWindowsToOtherDesksNotEndClamshellSplitView) {
NewDesk();
ASSERT_EQ(2u, DesksController::Get()->desks().size());
auto win0 = CreateAppWindow(gfx::Rect(0, 0, 250, 100));
auto win1 = CreateAppWindow(gfx::Rect(50, 50, 200, 200));
auto* overview_controller = OverviewController::Get();
ASSERT_TRUE(EnterOverview());
auto* overview_session = overview_controller->overview_session();
auto* generator = GetEventGenerator();
DragItemToPoint(overview_session->GetOverviewItemForWindow(win0.get()),
gfx::Point(0, 0), generator);
ASSERT_TRUE(overview_controller->InOverviewSession());
auto* split_view_controller =
SplitViewController::Get(Shell::GetPrimaryRootWindow());
EXPECT_TRUE(split_view_controller->InSplitViewMode());
EXPECT_TRUE(RootWindowController::ForWindow(win0.get())
->split_view_overview_session());
DragItemToPoint(overview_session->GetOverviewItemForWindow(win1.get()),
GetOverviewGridForRoot(Shell::GetPrimaryRootWindow())
->desks_bar_view()
->mini_views()[1]
->GetBoundsInScreen()
.CenterPoint(),
generator);
EXPECT_FALSE(DoesActiveDeskContainWindow(win1.get()));
ASSERT_TRUE(overview_controller->InOverviewSession());
EXPECT_TRUE(overview_session->IsEmpty());
EXPECT_TRUE(split_view_controller->InSplitViewMode());
}
TEST_P(DesksTest, RemoveDeskPreservesOverviewClipping) {
NewDesk();
NewDesk();
auto* controller = DesksController::Get();
Desk* desk2 = controller->GetDeskAtIndex(1);
Desk* desk3 = controller->GetDeskAtIndex(2);
ActivateDesk(desk3);
const int header_height = 32;
auto win0 = CreateAppWindow(gfx::Rect(200, 200));
win0->SetProperty(aura::client::kTopViewInset, header_height);
EXPECT_EQ(desk3->GetDeskContainerForRoot(Shell::GetPrimaryRootWindow()),
win0->parent());
ASSERT_TRUE(EnterOverview());
const gfx::Rect expected_clip = win0->layer()->GetTargetClipRect();
RemoveDesk(desk3);
ASSERT_EQ(desk2->GetDeskContainerForRoot(Shell::GetPrimaryRootWindow()),
win0->parent());
EXPECT_EQ(expected_clip, win0->layer()->GetTargetClipRect());
}
struct PerDeskZOrderTestCase {
std::string test_name;
bool multi_display;
std::vector<std::vector<int>> desk_1_windows;
std::vector<std::vector<int>> desk_2_windows;
std::set<int> adw_windows;
std::vector<int> activate_windows;
std::vector<std::vector<int>> expected_desk_1_windows_before;
std::vector<std::vector<int>> expected_desk_2_windows_before;
std::vector<int> move_windows;
std::vector<int> move_windows_to_other_display;
std::vector<int> close_windows;
std::vector<std::vector<int>> expected_desk_1_windows_after;
std::vector<std::vector<int>> expected_desk_2_windows_after;
int expected_desk_1_final_active_window;
};
class DesksPerDeskZOrderTest : public AshTestBase {
public:
DesksPerDeskZOrderTest() = default;
~DesksPerDeskZOrderTest() override = default;
void SetUp() override {
AshTestBase::SetUp();
NewDesk();
}
void RunTests(const std::vector<PerDeskZOrderTestCase>& tests) {
auto* controller = DesksController::Get();
auto* desk_1 = controller->GetDeskAtIndex(0);
auto* desk_2 = controller->GetDeskAtIndex(1);
for (const auto& test : tests) {
SCOPED_TRACE(test.test_name);
if (test.multi_display) {
UpdateDisplay("700x600,400x500");
} else {
UpdateDisplay("700x600");
}
display::Display secondary_display =
display::Screen::Get()->GetAllDisplays().back();
std::map<int, std::unique_ptr<aura::Window>> id_to_window;
std::map<aura::Window*, int> window_to_id;
auto populate_desk =
[&](Desk* desk, const std::vector<std::vector<int>>& desk_windows) {
SCOPED_TRACE("Create windows for " +
base::UTF16ToUTF8(desk->name()));
ASSERT_TRUE(desk->is_active());
int offset = 0;
for (const auto& window_ids : desk_windows) {
for (int id : window_ids) {
auto window =
CreateAppWindow(gfx::Rect(offset + id, 0 + id, 100, 100));
window->SetTitle(u"TestWindow" + base::NumberToString16(id));
window_to_id[window.get()] = id;
id_to_window[id] = std::move(window);
}
offset += secondary_display.bounds().x();
}
};
populate_desk(desk_1, test.desk_1_windows);
ActivateDesk(desk_2);
populate_desk(desk_2, test.desk_2_windows);
ActivateDesk(desk_1);
for (int id : test.adw_windows) {
views::Widget::GetWidgetForNativeWindow(id_to_window.at(id).get())
->SetVisibleOnAllWorkspaces(true);
}
for (int id : test.activate_windows) {
wm::ActivateWindow(id_to_window.at(id).get());
}
auto verify_desk_preview_mirrored_layer_tree =
[&](Desk* desk, aura::Window* root,
const std::vector<int>& expected_windows,
const std::string& debug_info) {
SCOPED_TRACE("Verify " + base::UTF16ToUTF8(desk->name()) + " " +
root->GetName() + " " + debug_info);
ToggleOverview();
const ui::LayerTreeOwner* layer_tree_owner =
DesksTestApi::GetMirroredContentsLayerTreeForRootAndDesk(root,
desk);
const std::vector<raw_ptr<ui::Layer, VectorExperimental>>
mirrored_layers =
layer_tree_owner->root()->children().front()->children();
ASSERT_EQ(expected_windows.size(), mirrored_layers.size());
std::vector<gfx::Rect> actual_bounds, expected_bounds;
for (size_t i = 0; i < expected_windows.size(); i++) {
expected_bounds.push_back(
id_to_window[expected_windows[i]]->layer()->bounds());
actual_bounds.push_back(mirrored_layers[i]->bounds());
}
EXPECT_THAT(actual_bounds, ElementsAreArray(expected_bounds));
ToggleOverview();
};
auto verify_windows = [&](Desk* desk, aura::Window* root,
const std::vector<int>& expected_windows,
const std::string& debug_info) {
aura::Window* container = desk->GetDeskContainerForRoot(root);
std::vector<int> actual_windows;
for (aura::Window* child : container->children()) {
auto it = window_to_id.find(child);
if (it != window_to_id.end()) {
actual_windows.push_back(it->second);
}
}
ASSERT_EQ(expected_windows, actual_windows)
<< "Window mismatch " << debug_info << " on " << root->GetName()
<< ":" << desk->name();
};
auto root_windows = Shell::GetAllRootWindows();
ASSERT_EQ(test.multi_display ? 2u : 1u, root_windows.size());
ActivateDesk(desk_2);
for (size_t i = 0; i < root_windows.size(); i++) {
verify_windows(desk_2, root_windows[i],
test.expected_desk_2_windows_before[i], "before moving");
verify_desk_preview_mirrored_layer_tree(
desk_1, root_windows[i], test.expected_desk_1_windows_before[i],
"before");
verify_desk_preview_mirrored_layer_tree(
desk_2, root_windows[i], test.expected_desk_2_windows_before[i],
"before");
}
for (int id : test.move_windows) {
const auto& window = id_to_window.at(id);
wm::ActivateWindow(window.get());
ASSERT_TRUE(controller->MoveWindowFromActiveDeskTo(
window.get(), desk_1, window.get()->GetRootWindow(),
DesksMoveWindowFromActiveDeskSource::kShortcut));
}
for (int id : test.move_windows_to_other_display) {
const auto& window = id_to_window.at(id);
aura::Window* root_before_moving = window->GetRootWindow();
auto bounds = window->GetBoundsInScreen();
bounds.Offset(secondary_display.bounds().origin().x(), 0);
window->SetBoundsInScreen(bounds, secondary_display);
ASSERT_NE(root_before_moving, window->GetRootWindow());
}
for (int id : test.close_windows) {
auto it = id_to_window.find(id);
ASSERT_NE(it, id_to_window.end()) << "Test setup error";
window_to_id.erase(it->second.get());
id_to_window.erase(it);
}
ActivateDesk(desk_1);
for (size_t i = 0; i < root_windows.size(); i++) {
verify_windows(desk_1, root_windows[i],
test.expected_desk_1_windows_after[i], "after moving");
verify_desk_preview_mirrored_layer_tree(
desk_1, root_windows[i], test.expected_desk_1_windows_after[i],
"after");
verify_desk_preview_mirrored_layer_tree(
desk_2, root_windows[i], test.expected_desk_2_windows_after[i],
"after");
}
int actual_active_window_id = -1;
auto active_window_it = window_to_id.find(window_util::GetActiveWindow());
if (active_window_it != window_to_id.end()) {
actual_active_window_id = active_window_it->second;
}
ASSERT_EQ(test.expected_desk_1_final_active_window,
actual_active_window_id);
}
}
};
TEST_F(DesksPerDeskZOrderTest, SingleDisplay) {
RunTests(std::vector<PerDeskZOrderTestCase>{
{.test_name = "Single adw window 1",
.desk_1_windows = {{1}},
.desk_2_windows = {{}},
.adw_windows = {1},
.expected_desk_1_windows_before = {{1}},
.expected_desk_2_windows_before = {{1}},
.move_windows = {},
.close_windows = {},
.expected_desk_1_windows_after = {{1}},
.expected_desk_2_windows_after = {{1}},
.expected_desk_1_final_active_window = 1},
{.test_name = "Single adw window 2",
.desk_1_windows = {{1, 2, 3}},
.desk_2_windows = {{5, 4}},
.adw_windows = {1},
.expected_desk_1_windows_before = {{1, 2, 3}},
.expected_desk_2_windows_before = {{5, 4, 1}},
.move_windows = {},
.close_windows = {},
.expected_desk_1_windows_after = {{1, 2, 3}},
.expected_desk_2_windows_after = {{5, 4, 1}},
.expected_desk_1_final_active_window = 3},
{.test_name = "Single adw window 3",
.desk_1_windows = {{1, 2, 3}},
.desk_2_windows = {{5, 4}},
.adw_windows = {1},
.expected_desk_1_windows_before = {{1, 2, 3}},
.expected_desk_2_windows_before = {{5, 4, 1}},
.move_windows = {5},
.close_windows = {},
.expected_desk_1_windows_after = {{1, 2, 3, 5}},
.expected_desk_2_windows_after = {{4, 1}},
.expected_desk_1_final_active_window = 5},
{.test_name = "Single adw window 4",
.desk_1_windows = {{1, 2, 3}},
.desk_2_windows = {{5, 4}},
.adw_windows = {2},
.expected_desk_1_windows_before = {{1, 2, 3}},
.expected_desk_2_windows_before = {{5, 4, 2}},
.move_windows = {5},
.close_windows = {1},
.expected_desk_1_windows_after = {{2, 3, 5}},
.expected_desk_2_windows_after = {{4, 2}},
.expected_desk_1_final_active_window = 5},
{.test_name = "Single adw window 5",
.desk_1_windows = {{1, 2, 3, 4, 5}},
.desk_2_windows = {{6}},
.adw_windows = {3},
.expected_desk_1_windows_before = {{1, 2, 3, 4, 5}},
.expected_desk_2_windows_before = {{6, 3}},
.move_windows = {6},
.close_windows = {1, 2},
.expected_desk_1_windows_after = {{3, 4, 5, 6}},
.expected_desk_2_windows_after = {{3}},
.expected_desk_1_final_active_window = 6},
{.test_name = "Multiple adw windows 1",
.desk_1_windows = {{1, 2, 3, 4, 5}},
.desk_2_windows = {{6, 7}},
.adw_windows = {2, 4},
.expected_desk_1_windows_before = {{1, 2, 3, 4, 5}},
.expected_desk_2_windows_before = {{6, 7, 2, 4}},
.move_windows = {},
.close_windows = {},
.expected_desk_1_windows_after = {{1, 2, 3, 4, 5}},
.expected_desk_2_windows_after = {{6, 7, 2, 4}},
.expected_desk_1_final_active_window = 5},
{.test_name = "Multiple adw windows 2",
.desk_1_windows = {{1, 2, 3, 4, 5}},
.desk_2_windows = {{6, 7}},
.adw_windows = {1, 3, 5},
.expected_desk_1_windows_before = {{1, 2, 3, 4, 5}},
.expected_desk_2_windows_before = {{6, 7, 1, 3, 5}},
.move_windows = {},
.close_windows = {},
.expected_desk_1_windows_after = {{1, 2, 3, 4, 5}},
.expected_desk_2_windows_after = {{6, 7, 1, 3, 5}},
.expected_desk_1_final_active_window = 5},
{.test_name = "Multiple adw windows 3",
.desk_1_windows = {{1, 2}},
.desk_2_windows = {{}},
.adw_windows = {1, 2},
.expected_desk_1_windows_before = {{1, 2}},
.expected_desk_2_windows_before = {{1, 2}},
.move_windows = {},
.close_windows = {},
.expected_desk_1_windows_after = {{1, 2}},
.expected_desk_2_windows_after = {{1, 2}},
.expected_desk_1_final_active_window = 2},
{.test_name = "Multiple adw windows 4",
.desk_1_windows = {{1, 2, 3, 4}},
.desk_2_windows = {{}},
.adw_windows = {1, 4},
.activate_windows = {4, 3, 2, 1},
.expected_desk_1_windows_before = {{4, 3, 2, 1}},
.expected_desk_2_windows_before = {{1, 4}},
.move_windows = {},
.close_windows = {},
.expected_desk_1_windows_after = {{4, 3, 2, 1}},
.expected_desk_2_windows_after = {{1, 4}},
.expected_desk_1_final_active_window = 1},
{.test_name = "Multiple adw windows 5",
.desk_1_windows = {{1, 2, 3, 4}},
.desk_2_windows = {{5}},
.adw_windows = {1, 3},
.activate_windows = {1, 2, 3, 4},
.expected_desk_1_windows_before = {{1, 2, 3, 4}},
.expected_desk_2_windows_before = {{5, 1, 3}},
.move_windows = {},
.close_windows = {},
.expected_desk_1_windows_after = {{1, 2, 3, 4}},
.expected_desk_2_windows_after = {{5, 1, 3}},
.expected_desk_1_final_active_window = 4},
});
}
TEST_F(DesksPerDeskZOrderTest, MultiDisplaySingleADW) {
RunTests(std::vector<PerDeskZOrderTestCase>{
{.test_name = "Multiple displays single adw 1",
.multi_display = true,
.desk_1_windows = {{1}, {2, 3, 4}},
.desk_2_windows = {{}, {5}},
.adw_windows = {1},
.activate_windows = {1, 2, 3, 4},
.expected_desk_1_windows_before = {{1}, {2, 3, 4}},
.expected_desk_2_windows_before = {{1}, {5}},
.move_windows = {},
.close_windows = {},
.expected_desk_1_windows_after = {{1}, {2, 3, 4}},
.expected_desk_2_windows_after = {{1}, {5}},
.expected_desk_1_final_active_window = 4},
{.test_name = "Multiple displays single adw 2",
.multi_display = true,
.desk_1_windows = {{1}, {2, 3, 4}},
.desk_2_windows = {{}, {5}},
.adw_windows = {1},
.activate_windows = {1, 2, 3, 4},
.expected_desk_1_windows_before = {{1}, {2, 3, 4}},
.expected_desk_2_windows_before = {{1}, {5}},
.move_windows = {},
.close_windows = {1},
.expected_desk_1_windows_after = {{}, {2, 3, 4}},
.expected_desk_2_windows_after = {{}, {5}},
.expected_desk_1_final_active_window = 4},
{.test_name = "Multiple displays single adw 3",
.multi_display = true,
.desk_1_windows = {{1}, {2, 3, 4}},
.desk_2_windows = {{}, {5}},
.adw_windows = {1},
.activate_windows = {4, 3, 2, 1},
.expected_desk_1_windows_before = {{1}, {4, 3, 2}},
.expected_desk_2_windows_before = {{1}, {5}},
.move_windows = {},
.close_windows = {1},
.expected_desk_1_windows_after = {{}, {4, 3, 2}},
.expected_desk_2_windows_after = {{}, {5}},
.expected_desk_1_final_active_window = 2},
{.test_name = "Multiple displays single adw 4",
.multi_display = true,
.desk_1_windows = {{1}, {2, 3, 4}},
.desk_2_windows = {{}, {5}},
.adw_windows = {1},
.activate_windows = {4, 3, 2, 1},
.expected_desk_1_windows_before = {{1}, {4, 3, 2}},
.expected_desk_2_windows_before = {{1}, {5}},
.move_windows = {},
.close_windows = {},
.expected_desk_1_windows_after = {{1}, {4, 3, 2}},
.expected_desk_2_windows_after = {{1}, {5}},
.expected_desk_1_final_active_window = 1},
{.test_name = "Multiple displays single adw 5",
.multi_display = true,
.desk_1_windows = {{1}, {2, 3, 4}},
.desk_2_windows = {{}, {5}},
.adw_windows = {4},
.activate_windows = {1, 2, 4, 3},
.expected_desk_1_windows_before = {{1}, {2, 4, 3}},
.expected_desk_2_windows_before = {{}, {5, 4}},
.move_windows = {},
.close_windows = {},
.expected_desk_1_windows_after = {{1}, {2, 4, 3}},
.expected_desk_2_windows_after = {{}, {5, 4}},
.expected_desk_1_final_active_window = 3},
{.test_name = "Multiple displays single adw 6",
.multi_display = true,
.desk_1_windows = {{1, 2}, {3, 4}},
.desk_2_windows = {{5}, {6}},
.adw_windows = {3},
.activate_windows = {1, 2, 3, 4},
.expected_desk_1_windows_before = {{1, 2}, {3, 4}},
.expected_desk_2_windows_before = {{5}, {6, 3}},
.move_windows = {},
.close_windows = {},
.expected_desk_1_windows_after = {{1, 2}, {3, 4}},
.expected_desk_2_windows_after = {{5}, {6, 3}},
.expected_desk_1_final_active_window = 4},
{.test_name = "Multiple displays single adw 7",
.multi_display = true,
.desk_1_windows = {{1}, {2, 3, 4}},
.desk_2_windows = {{}, {5}},
.adw_windows = {1},
.activate_windows = {4, 3, 2, 1},
.expected_desk_1_windows_before = {{1}, {4, 3, 2}},
.expected_desk_2_windows_before = {{1}, {5}},
.move_windows = {5},
.close_windows = {},
.expected_desk_1_windows_after = {{1}, {4, 3, 2, 5}},
.expected_desk_2_windows_after = {{1}, {}},
.expected_desk_1_final_active_window = 5},
{.test_name = "Multiple displays single adw 8",
.multi_display = true,
.desk_1_windows = {{1}, {2, 3, 4}},
.desk_2_windows = {{5}, {}},
.adw_windows = {1},
.activate_windows = {4, 3, 2, 1},
.expected_desk_1_windows_before = {{1}, {4, 3, 2}},
.expected_desk_2_windows_before = {{5, 1}, {}},
.move_windows = {5},
.close_windows = {},
.expected_desk_1_windows_after = {{1, 5}, {4, 3, 2}},
.expected_desk_2_windows_after = {{1}, {}},
.expected_desk_1_final_active_window = 5},
{.test_name = "Multiple displays single adw 9",
.multi_display = true,
.desk_1_windows = {{}, {1, 2, 3}},
.desk_2_windows = {{}, {}},
.adw_windows = {1},
.expected_desk_1_windows_before = {{}, {1, 2, 3}},
.expected_desk_2_windows_before = {{}, {1}},
.move_windows = {},
.close_windows = {},
.expected_desk_1_windows_after = {{}, {1, 2, 3}},
.expected_desk_2_windows_after = {{}, {1}},
.expected_desk_1_final_active_window = 3},
{.test_name = "Multiple displays single adw 10",
.multi_display = true,
.desk_1_windows = {{1}, {2, 3, 4}},
.desk_2_windows = {{5}, {}},
.adw_windows = {4},
.activate_windows = {1, 4, 3, 2},
.expected_desk_1_windows_before = {{1}, {4, 3, 2}},
.expected_desk_2_windows_before = {{5}, {4}},
.move_windows = {},
.close_windows = {},
.expected_desk_1_windows_after = {{1}, {4, 3, 2}},
.expected_desk_2_windows_after = {{5}, {4}},
.expected_desk_1_final_active_window = 2},
});
}
TEST_F(DesksPerDeskZOrderTest, MultiDisplayMultipleADW) {
RunTests(std::vector<PerDeskZOrderTestCase>{
{.test_name = "Multiple displays multiple adw 1",
.multi_display = true,
.desk_1_windows = {{1}, {2, 3, 4}},
.desk_2_windows = {{}, {5}},
.adw_windows = {1, 4},
.activate_windows = {1, 2, 3, 4},
.expected_desk_1_windows_before = {{1}, {2, 3, 4}},
.expected_desk_2_windows_before = {{1}, {5, 4}},
.move_windows = {},
.close_windows = {},
.expected_desk_1_windows_after = {{1}, {2, 3, 4}},
.expected_desk_2_windows_after = {{1}, {5, 4}},
.expected_desk_1_final_active_window = 4},
{.test_name = "Multiple displays multiple adw 2",
.multi_display = true,
.desk_1_windows = {{1}, {2, 3, 4}},
.desk_2_windows = {{}, {5}},
.adw_windows = {1, 4},
.activate_windows = {2, 3, 4, 1},
.expected_desk_1_windows_before = {{1}, {2, 3, 4}},
.expected_desk_2_windows_before = {{1}, {5, 4}},
.move_windows = {},
.close_windows = {},
.expected_desk_1_windows_after = {{1}, {2, 3, 4}},
.expected_desk_2_windows_after = {{1}, {5, 4}},
.expected_desk_1_final_active_window = 1},
{.test_name = "Multiple displays multiple adw 3",
.multi_display = true,
.desk_1_windows = {{1}, {2, 3, 4}},
.desk_2_windows = {{}, {5}},
.adw_windows = {1, 4},
.activate_windows = {1, 2, 3, 4},
.expected_desk_1_windows_before = {{1}, {2, 3, 4}},
.expected_desk_2_windows_before = {{1}, {5, 4}},
.move_windows = {},
.close_windows = {1},
.expected_desk_1_windows_after = {{}, {2, 3, 4}},
.expected_desk_2_windows_after = {{}, {5, 4}},
.expected_desk_1_final_active_window = 4},
{.test_name = "Multiple displays multiple adw 4",
.multi_display = true,
.desk_1_windows = {{1}, {2, 3, 4}},
.desk_2_windows = {{}, {5}},
.adw_windows = {1, 4},
.activate_windows = {2, 3, 4, 1},
.expected_desk_1_windows_before = {{1}, {2, 3, 4}},
.expected_desk_2_windows_before = {{1}, {5, 4}},
.move_windows = {},
.close_windows = {1},
.expected_desk_1_windows_after = {{}, {2, 3, 4}},
.expected_desk_2_windows_after = {{}, {5, 4}},
.expected_desk_1_final_active_window = 4},
{.test_name = "Multiple displays multiple adw 5",
.multi_display = true,
.desk_1_windows = {{1}, {2, 3, 4}},
.desk_2_windows = {{}, {5}},
.adw_windows = {1, 4},
.activate_windows = {4, 3, 2, 1},
.expected_desk_1_windows_before = {{1}, {4, 3, 2}},
.expected_desk_2_windows_before = {{1}, {5, 4}},
.move_windows = {},
.close_windows = {4},
.expected_desk_1_windows_after = {{1}, {3, 2}},
.expected_desk_2_windows_after = {{1}, {5}},
.expected_desk_1_final_active_window = 1},
{.test_name = "Multiple displays multiple adw 6",
.multi_display = true,
.desk_1_windows = {{1}, {2, 3, 4}},
.desk_2_windows = {{}, {5}},
.adw_windows = {1, 4},
.activate_windows = {4, 3, 2, 1},
.expected_desk_1_windows_before = {{1}, {4, 3, 2}},
.expected_desk_2_windows_before = {{1}, {5, 4}},
.move_windows = {5},
.close_windows = {},
.expected_desk_1_windows_after = {{1}, {4, 3, 2, 5}},
.expected_desk_2_windows_after = {{1}, {4}},
.expected_desk_1_final_active_window = 5},
{.test_name = "Multiple displays multiple adw 7",
.multi_display = true,
.desk_1_windows = {{1}, {2, 3, 4}},
.desk_2_windows = {{}, {5}},
.adw_windows = {1, 4},
.activate_windows = {1, 2, 3, 4},
.expected_desk_1_windows_before = {{1}, {2, 3, 4}},
.expected_desk_2_windows_before = {{1}, {5, 4}},
.move_windows = {5},
.close_windows = {},
.expected_desk_1_windows_after = {{1}, {2, 3, 4, 5}},
.expected_desk_2_windows_after = {{1}, {4}},
.expected_desk_1_final_active_window = 5},
{.test_name = "Multiple displays multiple adw 8",
.multi_display = true,
.desk_1_windows = {{1}, {2, 3, 4}},
.desk_2_windows = {{5}, {}},
.adw_windows = {1, 4},
.activate_windows = {4, 3, 2, 1},
.expected_desk_1_windows_before = {{1}, {4, 3, 2}},
.expected_desk_2_windows_before = {{5, 1}, {4}},
.move_windows = {5},
.close_windows = {},
.expected_desk_1_windows_after = {{1, 5}, {4, 3, 2}},
.expected_desk_2_windows_after = {{1}, {4}},
.expected_desk_1_final_active_window = 5},
{.test_name = "Multiple displays multiple adw 9",
.multi_display = true,
.desk_1_windows = {{1}, {2, 3, 4}},
.desk_2_windows = {{5}, {}},
.adw_windows = {1, 4},
.activate_windows = {1, 2, 3, 4},
.expected_desk_1_windows_before = {{1}, {2, 3, 4}},
.expected_desk_2_windows_before = {{5, 1}, {4}},
.move_windows = {5},
.close_windows = {},
.expected_desk_1_windows_after = {{1, 5}, {2, 3, 4}},
.expected_desk_2_windows_after = {{1}, {4}},
.expected_desk_1_final_active_window = 5},
{.test_name = "Multiple displays multiple adw on same root 1",
.multi_display = true,
.desk_1_windows = {{1, 2}, {3, 4}},
.desk_2_windows = {{}, {5}},
.adw_windows = {1, 2},
.activate_windows = {4, 3, 2, 1},
.expected_desk_1_windows_before = {{2, 1}, {4, 3}},
.expected_desk_2_windows_before = {{1, 2}, {5}},
.move_windows = {},
.close_windows = {},
.expected_desk_1_windows_after = {{2, 1}, {4, 3}},
.expected_desk_2_windows_after = {{1, 2}, {5}},
.expected_desk_1_final_active_window = 1},
{.test_name = "Multiple displays multiple adw on same root 2",
.multi_display = true,
.desk_1_windows = {{1, 2}, {3, 4}},
.desk_2_windows = {{5}, {}},
.adw_windows = {1, 2},
.activate_windows = {4, 3, 2, 1},
.expected_desk_1_windows_before = {{2, 1}, {4, 3}},
.expected_desk_2_windows_before = {{5, 1, 2}, {}},
.move_windows = {},
.close_windows = {},
.expected_desk_1_windows_after = {{2, 1}, {4, 3}},
.expected_desk_2_windows_after = {{5, 1, 2}, {}},
.expected_desk_1_final_active_window = 1},
{.test_name = "Multiple displays multiple adw on same root 3",
.multi_display = true,
.desk_1_windows = {{1, 2}, {3, 4}},
.desk_2_windows = {{}, {5}},
.adw_windows = {1, 2},
.activate_windows = {4, 3, 2, 1},
.expected_desk_1_windows_before = {{2, 1}, {4, 3}},
.expected_desk_2_windows_before = {{1, 2}, {5}},
.move_windows = {5},
.close_windows = {},
.expected_desk_1_windows_after = {{2, 1}, {4, 3, 5}},
.expected_desk_2_windows_after = {{1, 2}, {}},
.expected_desk_1_final_active_window = 5},
{.test_name = "Multiple displays multiple adw on same root 4",
.multi_display = true,
.desk_1_windows = {{1}, {2, 3, 4}},
.desk_2_windows = {{5}, {}},
.adw_windows = {3, 4},
.activate_windows = {1, 2, 3, 4},
.expected_desk_1_windows_before = {{1}, {2, 3, 4}},
.expected_desk_2_windows_before = {{5}, {3, 4}},
.move_windows = {},
.close_windows = {},
.expected_desk_1_windows_after = {{1}, {2, 3, 4}},
.expected_desk_2_windows_after = {{5}, {3, 4}},
.expected_desk_1_final_active_window = 4},
});
}
TEST_F(DesksPerDeskZOrderTest, MultiDisplayMultipleAdwWithMoving) {
RunTests(std::vector<PerDeskZOrderTestCase>{
{.test_name = "Multiple displays moving windows 1",
.multi_display = true,
.desk_1_windows = {{1}, {}},
.desk_2_windows = {{}, {}},
.adw_windows = {1},
.activate_windows = {1},
.expected_desk_1_windows_before = {{1}, {}},
.expected_desk_2_windows_before = {{1}, {}},
.move_windows = {},
.move_windows_to_other_display = {1},
.close_windows = {},
.expected_desk_1_windows_after = {{}, {1}},
.expected_desk_2_windows_after = {{}, {1}},
.expected_desk_1_final_active_window = 1},
{.test_name = "Multiple displays moving windows 2",
.multi_display = true,
.desk_1_windows = {{1, 2}, {}},
.desk_2_windows = {{}, {}},
.adw_windows = {1, 2},
.activate_windows = {1, 2},
.expected_desk_1_windows_before = {{1, 2}, {}},
.expected_desk_2_windows_before = {{1, 2}, {}},
.move_windows = {},
.move_windows_to_other_display = {1},
.close_windows = {},
.expected_desk_1_windows_after = {{2}, {1}},
.expected_desk_2_windows_after = {{2}, {1}},
.expected_desk_1_final_active_window = 1},
{.test_name = "Multiple displays moving windows 3",
.multi_display = true,
.desk_1_windows = {{1}, {2, 3, 4}},
.desk_2_windows = {{}, {}},
.adw_windows = {1, 4},
.activate_windows = {1, 2, 3},
.expected_desk_1_windows_before = {{1}, {4, 2, 3}},
.expected_desk_2_windows_before = {{1}, {4}},
.move_windows = {},
.move_windows_to_other_display = {1},
.close_windows = {},
.expected_desk_1_windows_after = {{}, {4, 2, 3, 1}},
.expected_desk_2_windows_after = {{}, {1, 4}},
.expected_desk_1_final_active_window = 1},
});
}
using FloatAllDesksWithZOrderTest = AshTestBase;
TEST_F(FloatAllDesksWithZOrderTest, TrackOrderAfterUnfloat) {
NewDesk();
auto window = CreateAppWindow();
views::Widget::GetWidgetForNativeWindow(window.get())
->SetVisibleOnAllWorkspaces(true);
auto* desks_controller = DesksController::Get();
ASSERT_EQ(1u, desks_controller->visible_on_all_desks_windows().size());
ASSERT_TRUE(desks_util::IsWindowVisibleOnAllWorkspaces(window.get()));
EXPECT_TRUE(desks_util::BelongsToActiveDesk(window.get()));
for (auto& desk : desks_controller->desks()) {
for (aura::Window* root : Shell::GetAllRootWindows()) {
auto& adw_data = desk->all_desk_window_stacking().at(root);
ASSERT_EQ(adw_data.size(), 1u);
ASSERT_EQ(adw_data.begin()->window, window.get());
}
}
PressAndReleaseKey(ui::VKEY_F, ui::EF_ALT_DOWN | ui::EF_COMMAND_DOWN);
EXPECT_TRUE(WindowState::Get(window.get())->IsFloated());
for (auto& desk : desks_controller->desks()) {
for (aura::Window* root : Shell::GetAllRootWindows()) {
auto& adw_data = desk->all_desk_window_stacking().at(root);
ASSERT_EQ(adw_data.size(), 0u);
}
}
}
TEST_F(FloatAllDesksWithZOrderTest, FloatThenAllDesks) {
NewDesk();
auto window = CreateAppWindow();
PressAndReleaseKey(ui::VKEY_F, ui::EF_ALT_DOWN | ui::EF_COMMAND_DOWN);
EXPECT_TRUE(WindowState::Get(window.get())->IsFloated());
views::Widget::GetWidgetForNativeWindow(window.get())
->SetVisibleOnAllWorkspaces(true);
auto* desks_controller = DesksController::Get();
ASSERT_EQ(1u, desks_controller->visible_on_all_desks_windows().size());
for (auto& desk : desks_controller->desks()) {
desk->all_desk_window_stacking().empty();
}
views::Widget::GetWidgetForNativeWindow(window.get())
->SetVisibleOnAllWorkspaces(false);
ASSERT_EQ(0u, desks_controller->visible_on_all_desks_windows().size());
}
TEST_F(FloatAllDesksWithZOrderTest, AllDesksThenFloatThenClose) {
NewDesk();
auto window = CreateAppWindow();
views::Widget::GetWidgetForNativeWindow(window.get())
->SetVisibleOnAllWorkspaces(true);
PressAndReleaseKey(ui::VKEY_F, ui::EF_ALT_DOWN | ui::EF_COMMAND_DOWN);
EXPECT_TRUE(WindowState::Get(window.get())->IsFloated());
window.reset();
ActivateDesk(DesksController::Get()->GetDeskAtIndex(1));
}
constexpr char kUser1Email[] = "user1@desks";
constexpr char kUser2Email[] = "user2@desks";
class DesksMultiUserTest : public NoSessionAshTestBase {
public:
DesksMultiUserTest() = default;
DesksMultiUserTest(const DesksMultiUserTest&) = delete;
DesksMultiUserTest& operator=(const DesksMultiUserTest&) = delete;
~DesksMultiUserTest() override = default;
MultiUserWindowManager* multi_user_window_manager() {
return Shell::Get()->multi_user_window_manager();
}
PrefService* user_1_prefs() { return user_1_prefs_; }
PrefService* user_2_prefs() { return user_2_prefs_; }
void SetUp() override {
NoSessionAshTestBase::SetUp();
owned_user_1_prefs_ =
ash::TestPrefServiceProvider::CreateUserPrefServiceSimple();
user_1_prefs_ = owned_user_1_prefs_.get();
owned_user_2_prefs_ =
ash::TestPrefServiceProvider::CreateUserPrefServiceSimple();
user_2_prefs_ = owned_user_2_prefs_.get();
}
void TearDown() override {
user_1_prefs_ = nullptr;
user_2_prefs_ = nullptr;
NoSessionAshTestBase::TearDown();
}
void SimulateUser1Login() {
auto account_id = SimulateUserLogin({kUser1Email}, std::nullopt,
std::move(owned_user_1_prefs_));
MultiUserWindowManager::Get()->SetAnimationSpeedForTest(
MultiUserWindowManager::ANIMATION_SPEED_DISABLED);
GetSessionControllerClient()->SetSessionState(
session_manager::SessionState::ACTIVE);
}
void SimulateUser2Login() {
SimulateUserLogin({kUser2Email}, std::nullopt,
std::move(owned_user_2_prefs_));
}
AccountId GetUser1AccountId() const {
return AccountId::FromUserEmail(kUser1Email);
}
AccountId GetUser2AccountId() const {
return AccountId::FromUserEmail(kUser2Email);
}
void InitPrefsWithDesksRestoreData(PrefService* prefs) {
InitPrefsWithDesksRestoreData(
prefs, {std::string(), std::string(), std::string("code")});
}
void InitPrefsWithDesksRestoreData(PrefService* prefs,
std::vector<std::string> desk_names) {
DCHECK(prefs);
ScopedListPrefUpdate update(prefs, prefs::kDesksNamesList);
base::Value::List& pref_data = update.Get();
ASSERT_TRUE(pref_data.empty());
for (auto desk_name : desk_names) {
pref_data.Append(desk_name);
}
}
private:
std::unique_ptr<PrefService> owned_user_1_prefs_;
std::unique_ptr<PrefService> owned_user_2_prefs_;
raw_ptr<PrefService> user_1_prefs_ = nullptr;
raw_ptr<PrefService> user_2_prefs_ = nullptr;
};
TEST_F(DesksMultiUserTest, SwitchUsersBackAndForth) {
SimulateUser1Login();
auto* controller = DesksController::Get();
NewDesk();
NewDesk();
ASSERT_EQ(3u, controller->desks().size());
Desk* desk_1 = controller->GetDeskAtIndex(0);
Desk* desk_2 = controller->GetDeskAtIndex(1);
Desk* desk_3 = controller->GetDeskAtIndex(2);
auto win0 = CreateAppWindow(gfx::Rect(0, 0, 250, 100));
multi_user_window_manager()->SetWindowOwner(win0.get(), GetUser1AccountId());
EXPECT_TRUE(win0->IsVisible());
ActivateDesk(desk_2);
auto win1 = CreateAppWindow(gfx::Rect(50, 50, 200, 200));
multi_user_window_manager()->SetWindowOwner(win1.get(), GetUser1AccountId());
EXPECT_FALSE(win0->IsVisible());
EXPECT_TRUE(win1->IsVisible());
SimulateUser2Login();
EXPECT_FALSE(win0->IsVisible());
EXPECT_FALSE(win1->IsVisible());
EXPECT_TRUE(desk_1->is_active());
auto win2 = CreateAppWindow(gfx::Rect(0, 0, 250, 200));
multi_user_window_manager()->SetWindowOwner(win2.get(), GetUser2AccountId());
EXPECT_TRUE(win2->IsVisible());
ActivateDesk(desk_3);
auto win3 = CreateAppWindow(gfx::Rect(0, 0, 250, 200));
multi_user_window_manager()->SetWindowOwner(win3.get(), GetUser2AccountId());
EXPECT_FALSE(win0->IsVisible());
EXPECT_FALSE(win1->IsVisible());
EXPECT_FALSE(win2->IsVisible());
EXPECT_TRUE(win3->IsVisible());
SwitchActiveUser(GetUser1AccountId());
EXPECT_TRUE(desk_2->is_active());
EXPECT_FALSE(win0->IsVisible());
EXPECT_TRUE(win1->IsVisible());
EXPECT_FALSE(win2->IsVisible());
EXPECT_FALSE(win3->IsVisible());
SwitchActiveUser(GetUser2AccountId());
EXPECT_TRUE(desk_3->is_active());
EXPECT_FALSE(win0->IsVisible());
EXPECT_FALSE(win1->IsVisible());
EXPECT_FALSE(win2->IsVisible());
EXPECT_TRUE(win3->IsVisible());
}
TEST_F(DesksMultiUserTest, RemoveDesks) {
SimulateUser1Login();
auto* controller = DesksController::Get();
NewDesk();
ASSERT_EQ(2u, controller->desks().size());
Desk* desk_1 = controller->GetDeskAtIndex(0);
Desk* desk_2 = controller->GetDeskAtIndex(1);
auto win0 = CreateAppWindow(gfx::Rect(0, 0, 250, 100));
multi_user_window_manager()->SetWindowOwner(win0.get(), GetUser1AccountId());
EXPECT_TRUE(win0->IsVisible());
ActivateDesk(desk_2);
auto win1 = CreateAppWindow(gfx::Rect(50, 50, 200, 200));
auto win2 =
CreateAppWindow(gfx::Rect(50, 50, 200, 200), chromeos::AppType::ARC_APP);
auto win3 =
CreateAppWindow(gfx::Rect(50, 50, 200, 200), chromeos::AppType::NON_APP);
multi_user_window_manager()->SetWindowOwner(win2.get(), GetUser1AccountId());
multi_user_window_manager()->SetWindowOwner(win1.get(), GetUser1AccountId());
multi_user_window_manager()->SetWindowOwner(win3.get(), GetUser1AccountId());
EXPECT_FALSE(win0->IsVisible());
EXPECT_TRUE(win1->IsVisible());
EXPECT_TRUE(win2->IsVisible());
EXPECT_TRUE(win3->IsVisible());
SimulateUser2Login();
EXPECT_TRUE(desk_1->is_active());
EXPECT_FALSE(win0->IsVisible());
EXPECT_FALSE(win1->IsVisible());
EXPECT_FALSE(win2->IsVisible());
EXPECT_FALSE(win3->IsVisible());
auto win4 = CreateAppWindow(gfx::Rect(0, 0, 250, 200));
multi_user_window_manager()->SetWindowOwner(win4.get(), GetUser2AccountId());
EXPECT_TRUE(win4->IsVisible());
ActivateDesk(desk_2);
auto win5 = CreateAppWindow(gfx::Rect(0, 0, 250, 200));
multi_user_window_manager()->SetWindowOwner(win5.get(), GetUser2AccountId());
EXPECT_FALSE(win0->IsVisible());
EXPECT_FALSE(win1->IsVisible());
EXPECT_FALSE(win2->IsVisible());
EXPECT_FALSE(win3->IsVisible());
EXPECT_FALSE(win4->IsVisible());
EXPECT_TRUE(win5->IsVisible());
RemoveDesk(desk_2);
EXPECT_TRUE(desk_1->is_active());
auto* desk_1_container =
desk_1->GetDeskContainerForRoot(Shell::GetPrimaryRootWindow());
EXPECT_EQ(desk_1_container, win0->parent());
EXPECT_EQ(desk_1_container, win1->parent());
EXPECT_EQ(desk_1_container, win2->parent());
EXPECT_NE(desk_1_container, win3->parent());
EXPECT_EQ(desk_1_container, win4->parent());
EXPECT_EQ(desk_1_container, win5->parent());
EXPECT_TRUE(win4->IsVisible());
EXPECT_TRUE(win5->IsVisible());
EXPECT_FALSE(win3->IsVisible());
SwitchActiveUser(GetUser1AccountId());
EXPECT_TRUE(desk_1->is_active());
EXPECT_TRUE(win0->IsVisible());
EXPECT_TRUE(win1->IsVisible());
EXPECT_TRUE(win2->IsVisible());
EXPECT_FALSE(win3->IsVisible());
NewDesk();
NewDesk();
ASSERT_EQ(3u, controller->desks().size());
desk_2 = controller->GetDeskAtIndex(1);
Desk* desk_3 = controller->GetDeskAtIndex(2);
SwitchActiveUser(GetUser2AccountId());
ActivateDesk(desk_3);
auto win6 = CreateAppWindow(gfx::Rect(0, 0, 250, 200));
multi_user_window_manager()->SetWindowOwner(win5.get(), GetUser2AccountId());
SwitchActiveUser(GetUser1AccountId());
EXPECT_TRUE(desk_1->is_active());
RemoveDesk(desk_1);
SwitchActiveUser(GetUser2AccountId());
EXPECT_TRUE(desk_3->is_active());
EXPECT_TRUE(win6->IsVisible());
}
TEST_F(DesksMultiUserTest, SwitchingUsersEndsOverview) {
SimulateUser1Login();
OverviewController* overview_controller = OverviewController::Get();
EXPECT_TRUE(EnterOverview());
EXPECT_TRUE(overview_controller->InOverviewSession());
SimulateUser2Login();
EXPECT_FALSE(overview_controller->InOverviewSession());
}
using DesksRestoreMultiUserTest = DesksMultiUserTest;
TEST_F(DesksRestoreMultiUserTest, DesksRestoredFromPrimaryUserPrefsOnly) {
constexpr int kDefaultActiveDesk = 0;
constexpr int kUser1StoredActiveDesk = 2;
InitPrefsWithDesksRestoreData(user_1_prefs());
user_1_prefs()->SetInteger(prefs::kDesksActiveDesk, kUser1StoredActiveDesk);
SimulateUser1Login();
auto* controller = DesksController::Get();
const auto& desks = controller->desks();
auto verify_desks = [&](const std::string& trace_name) {
SCOPED_TRACE(trace_name);
EXPECT_EQ(3u, desks.size());
EXPECT_EQ(u"Desk 1", desks[0]->name());
EXPECT_EQ(u"Desk 2", desks[1]->name());
EXPECT_EQ(u"code", desks[2]->name());
EXPECT_FALSE(desks[0]->is_name_set_by_user());
EXPECT_FALSE(desks[1]->is_name_set_by_user());
EXPECT_TRUE(desks[2]->is_name_set_by_user());
};
verify_desks("Before switching users");
EXPECT_EQ(desks[kUser1StoredActiveDesk]->container_id(),
desks_util::GetActiveDeskContainerId());
SimulateUser2Login();
verify_desks("After switching users");
EXPECT_EQ(desks[kDefaultActiveDesk]->container_id(),
desks_util::GetActiveDeskContainerId());
ActivateDesk(desks[1].get());
EXPECT_EQ(user_1_prefs()->GetInteger(prefs::kDesksActiveDesk),
kUser1StoredActiveDesk);
SwitchActiveUser(GetUser1AccountId());
EXPECT_EQ(desks[kUser1StoredActiveDesk]->container_id(),
desks_util::GetActiveDeskContainerId());
}
TEST_F(DesksRestoreMultiUserTest,
ChangesMadeBySecondaryUserAffectsOnlyPrimaryUserPrefs) {
InitPrefsWithDesksRestoreData(user_1_prefs());
SimulateUser1Login();
auto* controller = DesksController::Get();
const auto& desks = controller->desks();
ASSERT_EQ(3u, desks.size());
ActivateDesk(controller->desks().back().get());
EXPECT_EQ(user_1_prefs()->GetInteger(prefs::kDesksActiveDesk), 2);
SimulateUser2Login();
NewDesk();
EXPECT_THAT(GetDeskRestoreNames(user_1_prefs()),
ElementsAre("", "", "code", ""));
EXPECT_THAT(GetDeskRestoreNames(user_2_prefs()), ElementsAre());
RemoveDesk(desks[1].get());
EXPECT_THAT(GetDeskRestoreNames(user_1_prefs()), ElementsAre("", "code", ""));
EXPECT_THAT(GetDeskRestoreNames(user_2_prefs()), ElementsAre());
EXPECT_EQ(user_1_prefs()->GetInteger(prefs::kDesksActiveDesk), 1);
controller->ReorderDesk(2, 1);
EXPECT_THAT(GetDeskRestoreNames(user_1_prefs()), ElementsAre("", "", "code"));
EXPECT_THAT(GetDeskRestoreNames(user_2_prefs()), ElementsAre());
EXPECT_EQ(user_1_prefs()->GetInteger(prefs::kDesksActiveDesk), 2);
}
TEST_F(DesksRestoreMultiUserTest,
DeskIndexChangesMadeByActiveUserAffectsAllUsers) {
const int n_desks_per_user = 4;
int user_1_active_desk_index = 3;
user_1_prefs()->SetInteger(prefs::kDesksActiveDesk, user_1_active_desk_index);
InitPrefsWithDesksRestoreData(user_1_prefs(),
std::vector<std::string>{"0", "1", "2", "3"});
SimulateUser1Login();
auto* controller = DesksController::Get();
const auto& desks = controller->desks();
ASSERT_EQ(4u, desks.size());
EXPECT_EQ(desks[user_1_active_desk_index]->container_id(),
desks_util::GetActiveDeskContainerId());
int user_2_active_desk_index = 2;
SimulateUser2Login();
ActivateDesk(desks[user_2_active_desk_index].get());
EXPECT_EQ(desks[user_2_active_desk_index]->container_id(),
desks_util::GetActiveDeskContainerId());
EXPECT_EQ(user_1_active_desk_index,
user_1_prefs()->GetInteger(prefs::kDesksActiveDesk));
std::vector<std::unique_ptr<aura::Window>> user1_windows;
std::vector<std::unique_ptr<aura::Window>> user2_windows;
for (int i = 0; i < n_desks_per_user; i++) {
user1_windows.push_back(CreateAppWindow());
user2_windows.push_back(CreateAppWindow());
multi_user_window_manager()->SetWindowOwner(user1_windows[i].get(),
GetUser1AccountId());
multi_user_window_manager()->SetWindowOwner(user2_windows[i].get(),
GetUser2AccountId());
controller->SendToDeskAtIndex(user1_windows[i].get(), i);
controller->SendToDeskAtIndex(user2_windows[i].get(), i);
EXPECT_EQ(i,
user1_windows[i]->GetProperty(aura::client::kWindowWorkspaceKey));
EXPECT_EQ(i,
user2_windows[i]->GetProperty(aura::client::kWindowWorkspaceKey));
}
auto check_window_workspaces =
[&](const std::vector<int> desk_names_as_ints) {
DCHECK(n_desks_per_user == desk_names_as_ints.size());
for (int desk_index = 0; desk_index < n_desks_per_user; desk_index++) {
int desk_name_as_int = desk_names_as_ints[desk_index];
EXPECT_EQ(desk_index, user1_windows[desk_name_as_int]->GetProperty(
aura::client::kWindowWorkspaceKey));
EXPECT_EQ(desk_index, user2_windows[desk_name_as_int]->GetProperty(
aura::client::kWindowWorkspaceKey));
}
};
controller->ReorderDesk(3, 1);
user_1_active_desk_index = 1;
user_2_active_desk_index = 3;
check_window_workspaces(std::vector<int>{0, 3, 1, 2});
EXPECT_THAT(GetDeskRestoreNames(user_1_prefs()),
ElementsAre("0", "3", "1", "2"));
EXPECT_THAT(GetDeskRestoreNames(user_2_prefs()), ElementsAre());
EXPECT_EQ(user_1_active_desk_index,
user_1_prefs()->GetInteger(prefs::kDesksActiveDesk));
EXPECT_EQ(desks[user_2_active_desk_index]->container_id(),
desks_util::GetActiveDeskContainerId());
SwitchActiveUser(GetUser1AccountId());
EXPECT_EQ(desks[user_1_active_desk_index]->container_id(),
desks_util::GetActiveDeskContainerId());
controller->ReorderDesk(0, 3);
user_1_active_desk_index = 0;
user_2_active_desk_index = 2;
check_window_workspaces(std::vector<int>{3, 1, 2, 0});
EXPECT_THAT(GetDeskRestoreNames(user_1_prefs()),
ElementsAre("3", "1", "2", "0"));
EXPECT_THAT(GetDeskRestoreNames(user_2_prefs()), ElementsAre());
EXPECT_EQ(user_1_active_desk_index,
user_1_prefs()->GetInteger(prefs::kDesksActiveDesk));
EXPECT_EQ(desks[user_1_active_desk_index]->container_id(),
desks_util::GetActiveDeskContainerId());
SwitchActiveUser(GetUser2AccountId());
EXPECT_EQ(desks[user_2_active_desk_index]->container_id(),
desks_util::GetActiveDeskContainerId());
}
}
class DesksAcceleratorsTest : public DesksTest {
public:
DesksAcceleratorsTest() = default;
DesksAcceleratorsTest(const DesksAcceleratorsTest&) = delete;
DesksAcceleratorsTest& operator=(const DesksAcceleratorsTest&) = delete;
~DesksAcceleratorsTest() override = default;
void SetUp() override {
DesksTest::SetUp();
auto* event_rewriter_controller = EventRewriterController::Get();
auto event_rewriter = std::make_unique<ui::EventRewriterAsh>(
&event_rewriter_delegate_, Shell::Get()->keyboard_capability(),
Shell::Get()->sticky_keys_controller(), false, &fake_ime_keyboard_);
event_rewriter_controller->AddEventRewriter(std::move(event_rewriter));
}
void SendAccelerator(ui::KeyboardCode key_code, int flags) {
ui::test::EventGenerator* generator = GetEventGenerator();
generator->PressKey(key_code, flags);
generator->ReleaseKey(key_code, flags);
}
void MoveOverviewFocusRing(OverviewSession* session) {
session->Move(false);
}
private:
ui::test::FakeEventRewriterAshDelegate event_rewriter_delegate_;
input_method::FakeImeKeyboard fake_ime_keyboard_;
};
namespace {
TEST_P(DesksAcceleratorsTest, NewDesk) {
auto* controller = DesksController::Get();
const int flags = ui::EF_COMMAND_DOWN | ui::EF_SHIFT_DOWN;
for (size_t num_desks = 1; num_desks < desks_util::GetMaxNumberOfDesks();
++num_desks) {
DeskSwitchAnimationWaiter waiter;
SendAccelerator(ui::VKEY_OEM_PLUS, flags);
waiter.Wait();
ASSERT_EQ(num_desks + 1, controller->desks().size());
EXPECT_TRUE(controller->desks().back()->is_active());
}
EXPECT_EQ(desks_util::GetMaxNumberOfDesks(), controller->desks().size());
SendAccelerator(ui::VKEY_OEM_PLUS, flags);
EXPECT_EQ(desks_util::GetMaxNumberOfDesks(), controller->desks().size());
}
TEST_P(DesksAcceleratorsTest, CannotRemoveLastDesk) {
auto* controller = DesksController::Get();
ASSERT_EQ(1u, controller->desks().size());
const int flags = ui::EF_COMMAND_DOWN | ui::EF_SHIFT_DOWN;
SendAccelerator(ui::VKEY_OEM_MINUS, flags);
ASSERT_EQ(1u, controller->desks().size());
}
TEST_P(DesksAcceleratorsTest, RemoveDesk) {
auto* controller = DesksController::Get();
NewDesk();
NewDesk();
ASSERT_EQ(3u, controller->desks().size());
Desk* desk_1 = controller->GetDeskAtIndex(0);
Desk* desk_2 = controller->GetDeskAtIndex(1);
Desk* desk_3 = controller->GetDeskAtIndex(2);
EXPECT_TRUE(desk_1->is_active());
const int flags = ui::EF_COMMAND_DOWN | ui::EF_SHIFT_DOWN;
DeskSwitchAnimationWaiter waiter;
SendAccelerator(ui::VKEY_OEM_MINUS, flags);
waiter.Wait();
ASSERT_EQ(2u, controller->desks().size());
EXPECT_TRUE(desk_2->is_active());
auto* overview_controller = OverviewController::Get();
EnterOverview();
EXPECT_TRUE(overview_controller->InOverviewSession());
SendAccelerator(ui::VKEY_OEM_MINUS, flags);
ASSERT_EQ(1u, controller->desks().size());
EXPECT_TRUE(desk_3->is_active());
EXPECT_TRUE(overview_controller->InOverviewSession());
}
TEST_P(DesksAcceleratorsTest, RemoveRightmostDesk) {
auto* controller = DesksController::Get();
NewDesk();
NewDesk();
ASSERT_EQ(3u, controller->desks().size());
Desk* desk_1 = controller->GetDeskAtIndex(0);
Desk* desk_2 = controller->GetDeskAtIndex(1);
Desk* desk_3 = controller->GetDeskAtIndex(2);
ActivateDesk(desk_3);
EXPECT_TRUE(desk_3->is_active());
const int flags = ui::EF_COMMAND_DOWN | ui::EF_SHIFT_DOWN;
{
DeskSwitchAnimationWaiter waiter;
SendAccelerator(ui::VKEY_OEM_MINUS, flags);
waiter.Wait();
}
ASSERT_EQ(2u, controller->desks().size());
EXPECT_TRUE(desk_2->is_active());
{
DeskSwitchAnimationWaiter waiter;
SendAccelerator(ui::VKEY_OEM_MINUS, flags);
waiter.Wait();
}
ASSERT_EQ(1u, controller->desks().size());
EXPECT_TRUE(desk_1->is_active());
}
TEST_P(DesksAcceleratorsTest, LeftRightDeskActivation) {
auto* controller = DesksController::Get();
NewDesk();
ASSERT_EQ(2u, controller->desks().size());
Desk* desk_1 = controller->GetDeskAtIndex(0);
Desk* desk_2 = controller->GetDeskAtIndex(1);
EXPECT_TRUE(desk_1->is_active());
const int flags = ui::EF_COMMAND_DOWN;
SendAccelerator(ui::VKEY_OEM_4, flags);
EXPECT_TRUE(desk_1->is_active());
{
DeskSwitchAnimationWaiter waiter;
SendAccelerator(ui::VKEY_OEM_6, flags);
waiter.Wait();
EXPECT_TRUE(desk_2->is_active());
}
SendAccelerator(ui::VKEY_OEM_6, flags);
EXPECT_TRUE(desk_2->is_active());
{
DeskSwitchAnimationWaiter waiter;
SendAccelerator(ui::VKEY_OEM_4, flags);
waiter.Wait();
EXPECT_TRUE(desk_1->is_active());
}
}
TEST_P(DesksAcceleratorsTest, MoveWindowLeftRightDesk) {
auto* controller = DesksController::Get();
NewDesk();
ASSERT_EQ(2u, controller->desks().size());
Desk* desk_1 = controller->GetDeskAtIndex(0);
Desk* desk_2 = controller->GetDeskAtIndex(1);
EXPECT_TRUE(desk_1->is_active());
auto window = CreateAppWindow(gfx::Rect(0, 0, 250, 100));
wm::ActivateWindow(window.get());
EXPECT_EQ(window.get(), window_util::GetActiveWindow());
const int flags = ui::EF_COMMAND_DOWN | ui::EF_SHIFT_DOWN;
SendAccelerator(ui::VKEY_OEM_4, flags);
EXPECT_EQ(window.get(), window_util::GetActiveWindow());
EXPECT_TRUE(DoesActiveDeskContainWindow(window.get()));
SendAccelerator(ui::VKEY_OEM_6, flags);
EXPECT_EQ(nullptr, window_util::GetActiveWindow());
EXPECT_TRUE(desk_1->windows().empty());
EXPECT_TRUE(base::Contains(desk_2->windows(), window.get()));
SendAccelerator(ui::VKEY_OEM_6, flags);
EXPECT_TRUE(desk_1->windows().empty());
EXPECT_EQ(nullptr, window_util::GetActiveWindow());
ActivateDesk(desk_2);
EXPECT_EQ(window.get(), window_util::GetActiveWindow());
SendAccelerator(ui::VKEY_OEM_6, flags);
EXPECT_EQ(window.get(), window_util::GetActiveWindow());
SendAccelerator(ui::VKEY_OEM_4, flags);
EXPECT_TRUE(desk_2->windows().empty());
EXPECT_EQ(nullptr, window_util::GetActiveWindow());
EXPECT_TRUE(base::Contains(desk_1->windows(), window.get()));
}
TEST_P(DesksAcceleratorsTest, MoveWindowLeftRightDeskOverview) {
auto* controller = DesksController::Get();
NewDesk();
ASSERT_EQ(2u, controller->desks().size());
Desk* desk_1 = controller->GetDeskAtIndex(0);
Desk* desk_2 = controller->GetDeskAtIndex(1);
EXPECT_TRUE(desk_1->is_active());
auto win0 = CreateAppWindow(gfx::Rect(0, 0, 250, 100));
auto win1 = CreateAppWindow(gfx::Rect(0, 0, 250, 100));
wm::ActivateWindow(win0.get());
EXPECT_EQ(win0.get(), window_util::GetActiveWindow());
auto* overview_controller = OverviewController::Get();
EnterOverview();
EXPECT_TRUE(overview_controller->InOverviewSession());
const int flags = ui::EF_COMMAND_DOWN | ui::EF_SHIFT_DOWN;
const size_t num_windows_before = desk_1->windows().size();
EXPECT_TRUE(desk_2->windows().empty());
SendAccelerator(ui::VKEY_OEM_6, flags);
ASSERT_EQ(num_windows_before, desk_1->windows().size());
EXPECT_TRUE(desk_2->windows().empty());
auto* overview_session = overview_controller->overview_session();
ASSERT_TRUE(overview_session);
while (!overview_session->GetFocusedWindow()) {
MoveOverviewFocusRing(overview_session);
}
EXPECT_EQ(win0.get(), overview_session->GetFocusedWindow());
SendAccelerator(ui::VKEY_OEM_6, flags);
EXPECT_FALSE(DoesActiveDeskContainWindow(win0.get()));
EXPECT_TRUE(base::Contains(desk_2->windows(), win0.get()));
EXPECT_TRUE(overview_controller->InOverviewSession());
MoveOverviewFocusRing(overview_session);
EXPECT_EQ(win1.get(), overview_session->GetFocusedWindow());
SendAccelerator(ui::VKEY_OEM_6, flags);
EXPECT_FALSE(DoesActiveDeskContainWindow(win1.get()));
EXPECT_TRUE(base::Contains(desk_2->windows(), win1.get()));
EXPECT_TRUE(overview_controller->InOverviewSession());
EXPECT_FALSE(overview_session->GetFocusedWindow());
}
TEST_P(DesksAcceleratorsTest, CannotMoveAlwaysOnTopWindows) {
auto* controller = DesksController::Get();
NewDesk();
ASSERT_EQ(2u, controller->desks().size());
Desk* desk_1 = controller->GetDeskAtIndex(0);
Desk* desk_2 = controller->GetDeskAtIndex(1);
EXPECT_TRUE(desk_1->is_active());
auto win0 = CreateAppWindow(gfx::Rect(0, 0, 250, 100));
win0->SetProperty(aura::client::kZOrderingKey,
ui::ZOrderLevel::kFloatingWindow);
wm::ActivateWindow(win0.get());
EXPECT_EQ(win0.get(), window_util::GetActiveWindow());
EXPECT_FALSE(DoesActiveDeskContainWindow(win0.get()));
EXPECT_FALSE(controller->MoveWindowFromActiveDeskTo(
win0.get(), desk_2, win0->GetRootWindow(),
DesksMoveWindowFromActiveDeskSource::kDragAndDrop));
const int flags = ui::EF_COMMAND_DOWN | ui::EF_SHIFT_DOWN;
SendAccelerator(ui::VKEY_OEM_4, flags);
EXPECT_EQ(win0.get(), window_util::GetActiveWindow());
EXPECT_TRUE(win0->IsVisible());
ActivateDesk(desk_2);
EXPECT_TRUE(win0->IsVisible());
}
TEST_P(DesksAcceleratorsTest, HitAcceleratorWhenAlreadyAtEdge) {
NewDesk();
gfx::ScopedAnimationDurationScaleMode regular_animations(
gfx::ScopedAnimationDurationScaleMode::NON_ZERO_DURATION);
const int flags = ui::EF_COMMAND_DOWN;
SendAccelerator(ui::VKEY_OEM_6, flags);
DeskAnimationBase* animation = DesksController::Get()->animation();
ASSERT_TRUE(animation);
base::RunLoop run_loop;
auto* desk_switch_animator =
animation->GetDeskSwitchAnimatorAtIndexForTesting(0);
ASSERT_TRUE(desk_switch_animator);
RootWindowDeskSwitchAnimatorTestApi(desk_switch_animator)
.SetOnEndingScreenshotTakenCallback(run_loop.QuitClosure());
run_loop.Run();
SendAccelerator(ui::VKEY_OEM_4, flags);
SendAccelerator(ui::VKEY_OEM_4, flags);
}
TEST_P(DesksAcceleratorsTest, AssignToAllDesksShortcut) {
base::HistogramTester histogram_tester;
NewDesk();
NewDesk();
auto* controller = DesksController::Get();
ASSERT_EQ(3u, controller->desks().size());
auto window_1 = CreateAppWindow(gfx::Rect(0, 0, 100, 100));
auto* widget_1 = views::Widget::GetWidgetForNativeWindow(window_1.get());
auto menu_delegate =
std::make_unique<chromeos::MoveToDesksMenuDelegate>(widget_1);
menu_delegate->ExecuteCommand(
chromeos::MoveToDesksMenuModel::CommandId::TOGGLE_ASSIGN_TO_ALL_DESKS,
0);
histogram_tester.ExpectBucketCount(
chromeos::kDesksAssignToAllDesksSourceHistogramName,
chromeos::DesksAssignToAllDesksSource::kMoveToDeskMenu, 1);
EXPECT_TRUE(widget_1->IsVisibleOnAllWorkspaces());
auto window_2 = CreateAppWindow(gfx::Rect(0, 0, 100, 100));
ASSERT_EQ(window_2.get(), window_util::GetActiveWindow());
SendAccelerator(ui::VKEY_A, ui::EF_COMMAND_DOWN | ui::EF_SHIFT_DOWN);
histogram_tester.ExpectBucketCount(
chromeos::kDesksAssignToAllDesksSourceHistogramName,
chromeos::DesksAssignToAllDesksSource::kKeyboardShortcut, 1);
EXPECT_TRUE(views::Widget::GetWidgetForNativeWindow(window_2.get())
->IsVisibleOnAllWorkspaces());
}
TEST_P(DesksAcceleratorsTest, IndexedDeskActivationShortcut) {
const int flags = ui::EF_COMMAND_DOWN | ui::EF_SHIFT_DOWN;
constexpr char kDesksSwitchHistogramName[] = "Ash.Desks.DesksSwitch";
base::HistogramTester histogram_tester;
NewDesk();
NewDesk();
NewDesk();
auto* controller = DesksController::Get();
auto& desks = controller->desks();
ASSERT_EQ(4u, desks.size());
ASSERT_TRUE(desks[0]->is_active());
{
DeskSwitchAnimationWaiter waiter;
SendAccelerator(ui::VKEY_3, flags);
waiter.Wait();
}
EXPECT_TRUE(desks[2]->is_active());
histogram_tester.ExpectBucketCount(
kDesksSwitchHistogramName, DesksSwitchSource::kIndexedDeskSwitchShortcut,
1);
SendAccelerator(ui::VKEY_5, flags);
EXPECT_TRUE(desks[2]->is_active());
histogram_tester.ExpectBucketCount(
kDesksSwitchHistogramName, DesksSwitchSource::kIndexedDeskSwitchShortcut,
1);
{
DeskSwitchAnimationWaiter waiter;
SendAccelerator(ui::VKEY_2, flags);
waiter.Wait();
}
EXPECT_TRUE(desks[1]->is_active());
histogram_tester.ExpectBucketCount(
kDesksSwitchHistogramName, DesksSwitchSource::kIndexedDeskSwitchShortcut,
2);
EnterOverview();
ASSERT_TRUE(OverviewController::Get()->InOverviewSession());
SendAccelerator(ui::VKEY_2, flags);
EXPECT_TRUE(desks[1]->is_active());
EXPECT_FALSE(OverviewController::Get()->InOverviewSession());
histogram_tester.ExpectBucketCount(
kDesksSwitchHistogramName, DesksSwitchSource::kIndexedDeskSwitchShortcut,
2);
}
class PerDeskShelfTest : public AshTestBase,
public ::testing::WithParamInterface<bool> {
public:
PerDeskShelfTest() = default;
PerDeskShelfTest(const PerDeskShelfTest&) = delete;
PerDeskShelfTest& operator=(const PerDeskShelfTest&) = delete;
~PerDeskShelfTest() override = default;
void SetUp() override {
if (GetParam()) {
scoped_feature_list_.InitAndEnableFeature(features::kPerDeskShelf);
} else {
scoped_feature_list_.InitAndDisableFeature(features::kPerDeskShelf);
}
AshTestBase::SetUp();
}
std::unique_ptr<aura::Window> CreateAppWithShelfItem(ShelfItemType type) {
auto window = CreateAppWindow(gfx::Rect(0, 0, 250, 100));
const ash::ShelfID shelf_id(base::StringPrintf("%d", current_shelf_id_++));
window->SetProperty(ash::kShelfIDKey, shelf_id.Serialize());
window->SetProperty(ash::kAppIDKey, shelf_id.app_id);
window->SetProperty<int>(ash::kShelfItemTypeKey, type);
ShelfItem item;
item.status = ShelfItemStatus::STATUS_RUNNING;
item.type = type;
item.id = shelf_id;
item.title = u"Test Window";
ShelfModel::Get()->Add(item,
std::make_unique<TestShelfItemDelegate>(item.id));
return window;
}
bool IsPerDeskShelfEnabled() const { return GetParam(); }
ShelfView* GetShelfView() const {
return GetPrimaryShelf()->GetShelfViewForTesting();
}
int GetShelfItemIndexForWindow(aura::Window* window) const {
const auto shelf_id =
ShelfID::Deserialize(window->GetProperty(kShelfIDKey));
EXPECT_FALSE(shelf_id.IsNull());
return ShelfModel::Get()->ItemIndexByID(shelf_id);
}
void VerifyViewVisibility(aura::Window* window,
bool expected_visibility) const {
const size_t index = GetShelfItemIndexForWindow(window);
auto* shelf_view = GetShelfView();
auto* view_model = shelf_view->view_model();
views::View* item_view = view_model->view_at(index);
const bool contained_in_visible_indices =
base::Contains(shelf_view->visible_views_indices(), index);
EXPECT_EQ(expected_visibility, item_view->GetVisible());
EXPECT_EQ(expected_visibility, contained_in_visible_indices);
}
void MoveWindowFromActiveDeskTo(aura::Window* window,
Desk* target_desk) const {
DesksController::Get()->MoveWindowFromActiveDeskTo(
window, target_desk, window->GetRootWindow(),
DesksMoveWindowFromActiveDeskSource::kDragAndDrop);
}
private:
base::test::ScopedFeatureList scoped_feature_list_;
int current_shelf_id_ = 0;
};
TEST_P(PerDeskShelfTest, MoveWindowOutOfActiveDesk) {
auto* controller = DesksController::Get();
NewDesk();
auto win0 = CreateAppWithShelfItem(ShelfItemType::TYPE_BROWSER_SHORTCUT);
aura::Window* browser = win0.get();
auto win1 = CreateAppWithShelfItem(ShelfItemType::TYPE_PINNED_APP);
aura::Window* pinned = win1.get();
auto win2 = CreateAppWithShelfItem(ShelfItemType::TYPE_APP);
aura::Window* app = win2.get();
VerifyViewVisibility(browser, true);
VerifyViewVisibility(pinned, true);
VerifyViewVisibility(app, true);
const bool visible_in_per_desk_shelf = IsPerDeskShelfEnabled() ? false : true;
Desk* desk_2 = controller->GetDeskAtIndex(1);
MoveWindowFromActiveDeskTo(app, desk_2);
VerifyViewVisibility(browser, true);
VerifyViewVisibility(pinned, true);
VerifyViewVisibility(app, visible_in_per_desk_shelf);
MoveWindowFromActiveDeskTo(pinned, desk_2);
MoveWindowFromActiveDeskTo(browser, desk_2);
VerifyViewVisibility(browser, true);
VerifyViewVisibility(pinned, true);
VerifyViewVisibility(app, visible_in_per_desk_shelf);
}
TEST_P(PerDeskShelfTest, DeskSwitching) {
auto* controller = DesksController::Get();
NewDesk();
NewDesk();
auto win0 = CreateAppWithShelfItem(ShelfItemType::TYPE_BROWSER_SHORTCUT);
aura::Window* browser = win0.get();
auto win1 = CreateAppWithShelfItem(ShelfItemType::TYPE_APP);
aura::Window* app1 = win1.get();
const bool visible_in_per_desk_shelf = IsPerDeskShelfEnabled() ? false : true;
Desk* desk_2 = controller->GetDeskAtIndex(1);
ActivateDesk(desk_2);
VerifyViewVisibility(browser, true);
VerifyViewVisibility(app1, visible_in_per_desk_shelf);
auto win2 = CreateAppWithShelfItem(ShelfItemType::TYPE_PINNED_APP);
aura::Window* pinned = win2.get();
VerifyViewVisibility(pinned, true);
Desk* desk_3 = controller->GetDeskAtIndex(2);
ActivateDesk(desk_3);
VerifyViewVisibility(browser, true);
VerifyViewVisibility(app1, visible_in_per_desk_shelf);
VerifyViewVisibility(pinned, true);
auto win3 = CreateAppWithShelfItem(ShelfItemType::TYPE_APP);
aura::Window* app2 = win3.get();
Desk* desk_1 = controller->GetDeskAtIndex(0);
ActivateDesk(desk_1);
VerifyViewVisibility(browser, true);
VerifyViewVisibility(app1, true);
VerifyViewVisibility(pinned, true);
VerifyViewVisibility(app2, visible_in_per_desk_shelf);
}
TEST_P(PerDeskShelfTest, RemoveInactiveDesk) {
auto* controller = DesksController::Get();
NewDesk();
auto win0 = CreateAppWithShelfItem(ShelfItemType::TYPE_APP);
aura::Window* app1 = win0.get();
auto win1 = CreateAppWithShelfItem(ShelfItemType::TYPE_APP);
aura::Window* app2 = win1.get();
const bool visible_in_per_desk_shelf = IsPerDeskShelfEnabled() ? false : true;
Desk* desk_2 = controller->GetDeskAtIndex(1);
ActivateDesk(desk_2);
VerifyViewVisibility(app1, visible_in_per_desk_shelf);
VerifyViewVisibility(app2, visible_in_per_desk_shelf);
Desk* desk_1 = controller->GetDeskAtIndex(0);
RemoveDesk(desk_1);
VerifyViewVisibility(app1, true);
VerifyViewVisibility(app2, true);
}
TEST_P(PerDeskShelfTest, RemoveActiveDesk) {
auto* controller = DesksController::Get();
NewDesk();
auto win0 = CreateAppWithShelfItem(ShelfItemType::TYPE_APP);
aura::Window* app1 = win0.get();
const bool visible_in_per_desk_shelf = IsPerDeskShelfEnabled() ? false : true;
Desk* desk_2 = controller->GetDeskAtIndex(1);
ActivateDesk(desk_2);
VerifyViewVisibility(app1, visible_in_per_desk_shelf);
auto win1 = CreateAppWithShelfItem(ShelfItemType::TYPE_APP);
aura::Window* app2 = win1.get();
RemoveDesk(desk_2);
VerifyViewVisibility(app1, true);
VerifyViewVisibility(app2, true);
}
TEST_P(PerDeskShelfTest, ShelfViewTransformUpdatedForScrollWhenSwitchingDesks) {
ScrollableShelfView* scrollable_shelf_view = GetPrimaryShelf()
->shelf_widget()
->hotseat_widget()
->scrollable_shelf_view();
ShelfView* shelf_view = scrollable_shelf_view->shelf_view();
ShelfViewTestAPI shelf_view_test_api(shelf_view);
shelf_view_test_api.SetAnimationDuration(base::Milliseconds(1));
NewDesk();
ScrollArrowView* right_arrow = scrollable_shelf_view->right_arrow();
std::vector<std::unique_ptr<aura::Window>> windows;
while (!right_arrow->GetVisible()) {
windows.push_back(CreateAppWithShelfItem(ShelfItemType::TYPE_APP));
shelf_view_test_api.RunMessageLoopUntilAnimationsDone();
}
LeftClickOn(right_arrow);
shelf_view_test_api.RunMessageLoopUntilAnimationsDone();
const gfx::Transform scrolled_transform = shelf_view->GetTransform();
EXPECT_FALSE(scrolled_transform.IsIdentity());
ActivateDesk(DesksController::Get()->GetDeskAtIndex(1));
if (IsPerDeskShelfEnabled()) {
EXPECT_TRUE(shelf_view->GetTransform().IsIdentity());
} else {
EXPECT_EQ(scrolled_transform, shelf_view->GetTransform());
}
}
TEST_P(DesksTest, NameNudges) {
UpdateDisplay("1200x800");
auto* controller = DesksController::Get();
EnterOverview();
EXPECT_TRUE(OverviewController::Get()->InOverviewSession());
const auto* overview_grid =
GetOverviewGridForRoot(Shell::GetPrimaryRootWindow());
const auto* desks_bar_view = overview_grid->desks_bar_view();
ASSERT_TRUE(desks_bar_view->IsZeroState());
LeftClickOn(desks_bar_view->default_desk_button());
RunScheduledLayoutForAllOverviewDeskBars();
EXPECT_EQ(1u, desks_bar_view->mini_views().size());
auto* new_desk_button = desks_bar_view->new_desk_button();
EXPECT_TRUE(new_desk_button->GetEnabled());
for (size_t i = 1; i < desks_util::GetMaxNumberOfDesks(); ++i) {
LeftClickOn(new_desk_button);
RunScheduledLayoutForAllOverviewDeskBars();
auto* desk_name_view = desks_bar_view->mini_views()[i]->desk_name_view();
EXPECT_TRUE(desk_name_view->HasFocus());
EXPECT_EQ(std::u16string(), controller->GetDeskAtIndex(i)->name());
EXPECT_EQ(DesksController::GetDeskDefaultName(i - 1),
controller->GetDeskAtIndex(i - 1)->name());
TryScrollOverviewDeskBar(DeskBarScrollDirection::kRight);
RunScheduledLayoutForAllOverviewDeskBars();
}
}
TEST_P(DesksTest, NameNudgesMultiDisplay) {
UpdateDisplay("800x700,800x700");
EnterOverview();
EXPECT_TRUE(OverviewController::Get()->InOverviewSession());
auto root_windows = Shell::GetAllRootWindows();
ASSERT_EQ(2u, root_windows.size());
const auto* desks_bar_view_1 =
GetOverviewGridForRoot(root_windows[0])->desks_bar_view();
const auto* desks_bar_view_2 =
GetOverviewGridForRoot(root_windows[1])->desks_bar_view();
ASSERT_TRUE(desks_bar_view_1->IsZeroState());
ASSERT_TRUE(desks_bar_view_2->IsZeroState());
auto* default_desk_button_2 = desks_bar_view_2->default_desk_button();
EXPECT_TRUE(default_desk_button_2->GetEnabled());
LeftClickOn(default_desk_button_2);
RunScheduledLayoutForAllOverviewDeskBars();
EXPECT_FALSE(desks_bar_view_2->IsZeroState());
EXPECT_EQ(1u, desks_bar_view_2->mini_views().size());
auto* desk_name_view_2 = desks_bar_view_2->mini_views()[0]->desk_name_view();
EXPECT_TRUE(desk_name_view_2->HasFocus());
EXPECT_EQ(DesksController::GetDeskDefaultName(0),
desk_name_view_2->GetText());
ExitOverview();
EnterOverview();
desks_bar_view_1 = GetOverviewGridForRoot(root_windows[0])->desks_bar_view();
desks_bar_view_2 = GetOverviewGridForRoot(root_windows[1])->desks_bar_view();
ASSERT_TRUE(desks_bar_view_1->IsZeroState());
ASSERT_TRUE(desks_bar_view_2->IsZeroState());
auto* new_desk_button_1 = desks_bar_view_1->new_desk_button();
EXPECT_TRUE(new_desk_button_1->GetEnabled());
LeftClickOn(new_desk_button_1);
RunScheduledLayoutForAllOverviewDeskBars();
EXPECT_EQ(2u, desks_bar_view_1->mini_views().size());
auto* desk_name_view_1 = desks_bar_view_1->mini_views()[1]->desk_name_view();
desk_name_view_2 = desks_bar_view_2->mini_views()[1]->desk_name_view();
EXPECT_TRUE(desk_name_view_1->HasFocus());
EXPECT_FALSE(desk_name_view_2->HasFocus());
EXPECT_EQ(std::u16string(), desk_name_view_1->GetText());
EXPECT_EQ(std::u16string(), desk_name_view_2->GetText());
auto* new_desk_button_2 = desks_bar_view_2->new_desk_button();
EXPECT_TRUE(new_desk_button_2->GetEnabled());
GestureTapOn(new_desk_button_2);
RunScheduledLayoutForAllOverviewDeskBars();
EXPECT_EQ(3u, desks_bar_view_1->mini_views().size());
desk_name_view_1 = desks_bar_view_1->mini_views()[2]->desk_name_view();
desk_name_view_2 = desks_bar_view_2->mini_views()[2]->desk_name_view();
EXPECT_FALSE(desk_name_view_1->HasFocus());
EXPECT_TRUE(desk_name_view_2->HasFocus());
EXPECT_EQ(std::u16string(), desk_name_view_1->GetText());
EXPECT_EQ(std::u16string(), desk_name_view_2->GetText());
}
TEST_P(DesksTest, ClickingOverviewGridUnfocusesDeskNameView) {
NewDesk();
auto* overview_controller = OverviewController::Get();
EnterOverview();
EXPECT_TRUE(overview_controller->InOverviewSession());
auto* overview_grid = GetOverviewGridForRoot(Shell::GetPrimaryRootWindow());
const auto* desks_bar_view = overview_grid->desks_bar_view();
ASSERT_EQ(2u, desks_bar_view->mini_views().size());
auto* desk_name_view = desks_bar_view->mini_views()[0]->desk_name_view();
desk_name_view->RequestFocus();
ASSERT_TRUE(desk_name_view->HasFocus());
auto* event_generator = GetEventGenerator();
event_generator->MoveMouseTo(
OverviewGridTestApi(overview_grid).bounds().CenterPoint());
event_generator->ClickLeftButton();
EXPECT_FALSE(desk_name_view->HasFocus());
EXPECT_TRUE(overview_controller->InOverviewSession());
}
TEST_P(DesksTest, ScrollableDesks) {
UpdateDisplay("201x400");
EnterOverview();
EXPECT_TRUE(OverviewController::Get()->InOverviewSession());
auto* root_window = Shell::GetPrimaryRootWindow();
const auto* desks_bar_view =
GetOverviewGridForRoot(root_window)->desks_bar_view();
ASSERT_TRUE(desks_bar_view->IsZeroState());
LeftClickOn(desks_bar_view->default_desk_button());
RunScheduledLayoutForAllOverviewDeskBars();
EXPECT_EQ(1u, desks_bar_view->mini_views().size());
auto* new_desk_button = desks_bar_view->new_desk_button();
const int x_scroll_delta = 500;
gfx::Rect display_bounds =
screen_util::GetDisplayWorkAreaBoundsInScreenForActiveDeskContainer(
root_window);
auto* event_generator = GetEventGenerator();
for (size_t i = 1; i < desks_util::GetMaxNumberOfDesks(); i++) {
gfx::Rect new_desk_button_bounds = new_desk_button->GetBoundsInScreen();
EXPECT_TRUE(display_bounds.Contains(new_desk_button_bounds));
LeftClickOn(new_desk_button);
RunScheduledLayoutForAllOverviewDeskBars();
event_generator->MoveMouseWheel(-x_scroll_delta, 0);
}
auto* controller = DesksController::Get();
EXPECT_EQ(desks_util::GetMaxNumberOfDesks(), controller->desks().size());
EXPECT_FALSE(controller->CanCreateDesks());
EXPECT_TRUE(display_bounds.Contains(new_desk_button->GetBoundsInScreen()));
EXPECT_FALSE(display_bounds.Contains(
desks_bar_view->mini_views()[0]->GetBoundsInScreen()));
event_generator->MoveMouseWheel(x_scroll_delta, 0);
EXPECT_TRUE(display_bounds.Contains(
desks_bar_view->mini_views()[0]->GetBoundsInScreen()));
EXPECT_FALSE(display_bounds.Contains(new_desk_button->GetBoundsInScreen()));
}
TEST_P(DesksTest, ScrollButtonsVisibility) {
const auto is_scroll_button_visible = [](DeskBarScrollDirection direction) {
ScrollArrowButton* scroll_arrow = nullptr;
switch (direction) {
case DeskBarScrollDirection::kLeft:
scroll_arrow = DesksTestApi::GetDeskBarLeftScrollButton(
DeskBarViewBase::Type::kOverview);
break;
case DeskBarScrollDirection::kRight:
scroll_arrow = DesksTestApi::GetDeskBarRightScrollButton(
DeskBarViewBase::Type::kOverview);
break;
}
return IsLazyInitViewVisible(scroll_arrow);
};
UpdateDisplay("600x400");
for (size_t i = 1; i < desks_util::GetMaxNumberOfDesks(); i++) {
NewDesk();
}
EXPECT_EQ(DesksController::Get()->desks().size(),
desks_util::GetMaxNumberOfDesks());
TabletModeControllerTestApi().EnterTabletMode();
EnterOverview();
EXPECT_TRUE(OverviewController::Get()->InOverviewSession());
auto* desks_bar =
GetOverviewGridForRoot(Shell::GetPrimaryRootWindow())->desks_bar_view();
auto* event_generator = GetEventGenerator();
event_generator->MoveMouseTo(desks_bar->GetBoundsInScreen().CenterPoint());
const int x_scroll_delta = 1000;
event_generator->MoveMouseWheel(x_scroll_delta, 0);
EXPECT_FALSE(is_scroll_button_visible(DeskBarScrollDirection::kLeft));
EXPECT_TRUE(is_scroll_button_visible(DeskBarScrollDirection::kRight));
TryScrollOverviewDeskBar(DeskBarScrollDirection::kRight);
EXPECT_TRUE(is_scroll_button_visible(DeskBarScrollDirection::kLeft));
TryScrollOverviewDeskBar(DeskBarScrollDirection::kLeft);
EXPECT_TRUE(is_scroll_button_visible(DeskBarScrollDirection::kRight));
event_generator->MoveMouseTo(desks_bar->GetBoundsInScreen().CenterPoint());
event_generator->MoveMouseWheel(-x_scroll_delta, 0);
EXPECT_TRUE(is_scroll_button_visible(DeskBarScrollDirection::kLeft));
EXPECT_FALSE(is_scroll_button_visible(DeskBarScrollDirection::kRight));
}
TEST_P(DesksTest, GradientsVisibility) {
UpdateDisplay("800x150");
const size_t max_desks_size = desks_util::GetMaxNumberOfDesks();
for (size_t i = 1; i < max_desks_size; i++) {
NewDesk();
}
EnterOverview();
auto* desks_bar =
GetOverviewGridForRoot(Shell::GetPrimaryRootWindow())->desks_bar_view();
auto* left_button = DesksTestApi::GetDeskBarLeftScrollButton(
DeskBarViewBase::Type::kOverview);
auto* right_button = DesksTestApi::GetDeskBarRightScrollButton(
DeskBarViewBase::Type::kOverview);
auto* scroll_view =
DesksTestApi::GetDeskBarScrollView(DeskBarViewBase::Type::kOverview);
ASSERT_TRUE(scroll_view);
EXPECT_EQ(0, scroll_view->GetVisibleRect().x());
ASSERT_TRUE(left_button);
EXPECT_FALSE(left_button->GetVisible());
EXPECT_FALSE(DesksTestApi::IsDeskBarLeftGradientVisible(
DeskBarViewBase::Type::kOverview));
ASSERT_TRUE(right_button);
EXPECT_TRUE(right_button->GetVisible());
EXPECT_TRUE(DesksTestApi::IsDeskBarRightGradientVisible(
DeskBarViewBase::Type::kOverview));
const gfx::Point center_point = desks_bar->bounds().CenterPoint();
ui::GestureEvent scroll_begin(
center_point.x(), center_point.y(), ui::EF_NONE, base::TimeTicks::Now(),
ui::GestureEventDetails(ui::EventType::kGestureScrollBegin, 1, 0));
scroll_view->OnGestureEvent(&scroll_begin);
ui::GestureEvent scroll_update(
center_point.x(), center_point.y(), ui::EF_NONE, base::TimeTicks::Now(),
ui::GestureEventDetails(ui::EventType::kGestureScrollUpdate, -100, 0));
scroll_view->OnGestureEvent(&scroll_update);
EXPECT_TRUE(scroll_view->is_scrolling());
EXPECT_TRUE(left_button->GetVisible());
EXPECT_TRUE(DesksTestApi::IsDeskBarLeftGradientVisible(
DeskBarViewBase::Type::kOverview));
EXPECT_TRUE(right_button->GetVisible());
EXPECT_TRUE(DesksTestApi::IsDeskBarRightGradientVisible(
DeskBarViewBase::Type::kOverview));
ui::GestureEvent second_scroll_update(
center_point.x() - 100, center_point.y(), ui::EF_NONE,
base::TimeTicks::Now(),
ui::GestureEventDetails(ui::EventType::kGestureScrollUpdate, 100, 0));
scroll_view->OnGestureEvent(&second_scroll_update);
EXPECT_TRUE(scroll_view->is_scrolling());
EXPECT_FALSE(left_button->GetVisible());
EXPECT_FALSE(DesksTestApi::IsDeskBarLeftGradientVisible(
DeskBarViewBase::Type::kOverview));
EXPECT_TRUE(right_button->GetVisible());
EXPECT_TRUE(DesksTestApi::IsDeskBarRightGradientVisible(
DeskBarViewBase::Type::kOverview));
ui::GestureEvent scroll_end(
center_point.x(), center_point.y(), ui::EF_NONE, base::TimeTicks::Now(),
ui::GestureEventDetails(ui::EventType::kGestureScrollEnd));
scroll_view->OnGestureEvent(&scroll_end);
EXPECT_FALSE(scroll_view->is_scrolling());
EXPECT_FALSE(left_button->GetVisible());
EXPECT_FALSE(DesksTestApi::IsDeskBarLeftGradientVisible(
DeskBarViewBase::Type::kOverview));
EXPECT_TRUE(right_button->GetVisible());
EXPECT_TRUE(DesksTestApi::IsDeskBarRightGradientVisible(
DeskBarViewBase::Type::kOverview));
LeftClickOn(right_button);
EXPECT_TRUE(left_button->GetVisible());
EXPECT_FALSE(DesksTestApi::IsDeskBarLeftGradientVisible(
DeskBarViewBase::Type::kOverview));
EXPECT_TRUE(right_button->GetVisible());
EXPECT_TRUE(DesksTestApi::IsDeskBarRightGradientVisible(
DeskBarViewBase::Type::kOverview));
while (right_button->GetVisible()) {
LeftClickOn(right_button);
}
EXPECT_EQ(scroll_view->contents()->bounds().width() - scroll_view->width(),
scroll_view->GetVisibleRect().x());
EXPECT_TRUE(left_button->GetVisible());
EXPECT_TRUE(DesksTestApi::IsDeskBarLeftGradientVisible(
DeskBarViewBase::Type::kOverview));
EXPECT_FALSE(right_button->GetVisible());
EXPECT_FALSE(DesksTestApi::IsDeskBarRightGradientVisible(
DeskBarViewBase::Type::kOverview));
}
TEST_P(DesksTest, ContinueScrollBar) {
const int scroll_timeout_ms = 20;
base::AutoReset<base::TimeDelta> auto_reset =
DesksTestApi::SetScrollTimeInterval(
base::Milliseconds(scroll_timeout_ms));
UpdateDisplay("800x150");
const size_t max_desks_size = desks_util::GetMaxNumberOfDesks();
for (size_t i = 1; i < max_desks_size; i++) {
NewDesk();
}
auto* desks_controller = DesksController::Get();
EXPECT_EQ(desks_controller->desks().size(), max_desks_size);
EnterOverview();
EXPECT_TRUE(OverviewController::Get()->InOverviewSession());
auto* desks_bar =
GetOverviewGridForRoot(Shell::GetPrimaryRootWindow())->desks_bar_view();
views::ScrollView* scroll_view =
DesksTestApi::GetDeskBarScrollView(DeskBarViewBase::Type::kOverview);
ASSERT_TRUE(scroll_view);
const int page_size = scroll_view->width();
const auto mini_views = desks_bar->mini_views();
const int mini_view_width = mini_views[0]->bounds().width();
int desks_in_one_page = page_size / mini_view_width;
float fractional_page = static_cast<float>(page_size % mini_view_width) /
static_cast<float>(mini_view_width);
if (fractional_page > 0.5) {
desks_in_one_page++;
}
int current_index = 0;
ScrollArrowButton* left_button = DesksTestApi::GetDeskBarLeftScrollButton(
DeskBarViewBase::Type::kOverview);
ASSERT_TRUE(left_button);
ScrollArrowButton* right_button = DesksTestApi::GetDeskBarRightScrollButton(
DeskBarViewBase::Type::kOverview);
ASSERT_TRUE(right_button);
EXPECT_FALSE(left_button->GetVisible());
EXPECT_TRUE(right_button->GetVisible());
const int focus_ring_width_and_padding = 4;
auto* event_generator = GetEventGenerator();
event_generator->MoveMouseTo(right_button->GetBoundsInScreen().CenterPoint());
event_generator->PressLeftButton();
current_index += desks_in_one_page;
EXPECT_EQ(scroll_view->GetVisibleRect().x() + focus_ring_width_and_padding,
mini_views[current_index]->bounds().x());
EXPECT_TRUE(left_button->GetVisible());
EXPECT_TRUE(right_button->GetVisible());
WaitForMilliseconds(scroll_timeout_ms);
current_index += desks_in_one_page;
if (!features::Is16DesksEnabled()) {
EXPECT_EQ(
scroll_view->GetVisibleRect().right() - focus_ring_width_and_padding,
desks_bar->new_desk_button()->bounds().right());
} else {
EXPECT_EQ(scroll_view->GetVisibleRect().x() + focus_ring_width_and_padding,
mini_views[current_index]->bounds().x());
}
event_generator->ReleaseLeftButton();
for (int i = 0; i != 3; ++i) {
event_generator->ClickLeftButton();
}
EXPECT_EQ(scroll_view->GetVisibleRect().x(),
scroll_view->contents()->width() - page_size);
EXPECT_TRUE(left_button->GetVisible());
EXPECT_FALSE(right_button->GetVisible());
current_index = max_desks_size - 1;
event_generator->MoveTouch(left_button->GetBoundsInScreen().CenterPoint());
event_generator->PressTouch();
current_index -= (desks_in_one_page + 1);
EXPECT_EQ(scroll_view->GetVisibleRect().x() + focus_ring_width_and_padding,
mini_views[current_index]->bounds().x());
WaitForMilliseconds(scroll_timeout_ms);
current_index -= desks_in_one_page;
EXPECT_EQ(scroll_view->GetVisibleRect().x() + focus_ring_width_and_padding,
mini_views[current_index]->bounds().x());
event_generator->ReleaseTouch();
}
TEST_P(DesksTest, FocusedMiniViewIsVisible) {
UpdateDisplay("600x400");
for (size_t i = 1; i < desks_util::GetMaxNumberOfDesks(); i++) {
NewDesk();
}
EXPECT_EQ(DesksController::Get()->desks().size(),
desks_util::GetMaxNumberOfDesks());
auto window = CreateAppWindow(gfx::Rect(0, 0, 100, 100));
TabletModeControllerTestApi().EnterTabletMode();
EnterOverview();
EXPECT_TRUE(OverviewController::Get()->InOverviewSession());
auto* desks_bar =
GetOverviewGridForRoot(Shell::GetPrimaryRootWindow())->desks_bar_view();
ASSERT_TRUE(DesksTestApi::GetDeskBarRightScrollButton(
DeskBarViewBase::Type::kOverview));
auto mini_views = desks_bar->mini_views();
ASSERT_EQ(mini_views.size(), desks_util::GetMaxNumberOfDesks());
auto* generator = GetEventGenerator();
for (size_t i = 0; i < desks_util::GetMaxNumberOfDesks(); i++) {
PressAndReleaseKey(ui::VKEY_TAB);
const views::ScrollView* const scroll_view =
DesksTestApi::GetDeskBarScrollView(DeskBarViewBase::Type::kOverview);
ASSERT_TRUE(scroll_view);
EXPECT_TRUE(
scroll_view->GetVisibleRect().Contains(mini_views[i]->bounds()));
ASSERT_TRUE(TabUntil(
false, ViewFocused(mini_views[i]->desk_name_view()),
generator));
}
for (size_t i = desks_util::GetMaxNumberOfDesks() - 1; i > 0; i--) {
ASSERT_TRUE(TabUntil(
true, ViewFocused(mini_views[i - 1]->desk_name_view()),
generator));
const views::ScrollView* const scroll_view =
DesksTestApi::GetDeskBarScrollView(DeskBarViewBase::Type::kOverview);
ASSERT_TRUE(scroll_view);
EXPECT_TRUE(
scroll_view->GetVisibleRect().Contains(mini_views[i - 1]->bounds()));
}
}
TEST_P(DesksTest, ActiveDeskMiniViewIsVisible) {
for (size_t i = 1; i < desks_util::GetMaxNumberOfDesks(); i++) {
NewDesk();
ActivateDesk(DesksController::Get()->desks().back().get());
EnterOverview();
auto* desks_bar =
GetOverviewGridForRoot(Shell::GetPrimaryRootWindow())->desks_bar_view();
for (ash::DeskMiniView* mini_view : desks_bar->mini_views()) {
if (mini_view->desk()->is_active()) {
EXPECT_EQ(mini_view->size(), mini_view->GetVisibleBounds().size());
}
}
ExitOverview();
}
}
TEST_P(DesksTest, FocusedButtonIsVisible) {
for (size_t i = 1; i < desks_util::GetMaxNumberOfDesks() - 1; i++) {
NewDesk();
}
EnterOverview();
auto* desk_bar =
GetOverviewGridForRoot(Shell::GetPrimaryRootWindow())->desks_bar_view();
auto* new_desk_button = desk_bar->new_desk_button();
PressAndReleaseKey(ui::VKEY_TAB, ui::EF_SHIFT_DOWN);
EXPECT_TRUE(new_desk_button->GetVisible());
EXPECT_EQ(new_desk_button->size(),
new_desk_button->GetVisibleBounds().size());
ExitOverview();
}
TEST_P(DesksTest, VisibleOnAllDesksGlobalBounds) {
auto* controller = DesksController::Get();
NewDesk();
const Desk* desk_1 = controller->GetDeskAtIndex(0);
const Desk* desk_2 = controller->GetDeskAtIndex(1);
auto* root = Shell::GetPrimaryRootWindow();
const gfx::Rect window_initial_bounds(1, 1, 200, 200);
const gfx::Rect window_moved_bounds(200, 200, 250, 250);
auto window = CreateAppWindow(window_initial_bounds);
auto* widget = views::Widget::GetWidgetForNativeWindow(window.get());
ASSERT_EQ(window_initial_bounds, window->bounds());
widget->SetVisibleOnAllWorkspaces(true);
ASSERT_TRUE(desks_util::IsWindowVisibleOnAllWorkspaces(window.get()));
EXPECT_EQ(window_initial_bounds, window->bounds());
EXPECT_EQ(1u, controller->visible_on_all_desks_windows().size());
ActivateDesk(desk_2);
auto desk_2_children = desk_2->GetDeskContainerForRoot(root)->children();
EXPECT_EQ(1u, desk_2_children.size());
EXPECT_EQ(window.get(), desk_2_children[0]);
EXPECT_EQ(window_initial_bounds, window->bounds());
window->SetBounds(window_moved_bounds);
EXPECT_EQ(window_moved_bounds, window->bounds());
ActivateDesk(desk_1);
auto desk_1_children = desk_1->GetDeskContainerForRoot(root)->children();
EXPECT_EQ(1u, desk_1_children.size());
EXPECT_EQ(window.get(), desk_1_children[0]);
EXPECT_EQ(window_moved_bounds, window->bounds());
}
TEST_P(DesksTest, VisibleOnAllDesksActiveDeskRemoval) {
auto* controller = DesksController::Get();
NewDesk();
const Desk* desk_1 = controller->GetDeskAtIndex(0);
const Desk* desk_2 = controller->GetDeskAtIndex(1);
auto* root = Shell::GetPrimaryRootWindow();
auto win0 = CreateAppWindow(gfx::Rect(0, 0, 100, 100));
auto win1 = CreateAppWindow(gfx::Rect(1, 1, 150, 150));
auto* widget0 = views::Widget::GetWidgetForNativeWindow(win0.get());
auto* widget1 = views::Widget::GetWidgetForNativeWindow(win1.get());
widget0->SetVisibleOnAllWorkspaces(true);
widget1->SetVisibleOnAllWorkspaces(true);
ASSERT_TRUE(desks_util::IsWindowVisibleOnAllWorkspaces(win0.get()));
ASSERT_TRUE(desks_util::IsWindowVisibleOnAllWorkspaces(win1.get()));
RemoveDesk(desk_1);
auto desk_2_children = desk_2->GetDeskContainerForRoot(root)->children();
EXPECT_EQ(2u, desk_2_children.size());
EXPECT_TRUE(window_util::IsStackedBelow(win0.get(), win1.get()));
EXPECT_EQ(2u, controller->visible_on_all_desks_windows().size());
}
TEST_P(DesksTest, VisibleOnAllDesksMinimizedWindow) {
auto* controller = DesksController::Get();
NewDesk();
const Desk* desk_2 = controller->GetDeskAtIndex(1);
auto* root = Shell::GetPrimaryRootWindow();
auto window = CreateAppWindow(gfx::Rect(0, 0, 100, 100));
auto* widget = views::Widget::GetWidgetForNativeWindow(window.get());
auto* window_state = WindowState::Get(window.get());
window_state->Minimize();
ASSERT_TRUE(window_state->IsMinimized());
widget->SetVisibleOnAllWorkspaces(true);
ASSERT_TRUE(desks_util::IsWindowVisibleOnAllWorkspaces(window.get()));
EXPECT_TRUE(window_state->IsMinimized());
ActivateDesk(desk_2);
auto desk_2_children = desk_2->GetDeskContainerForRoot(root)->children();
EXPECT_EQ(1u, desk_2_children.size());
EXPECT_EQ(window.get(), desk_2_children[0]);
EXPECT_TRUE(window_state->IsMinimized());
}
TEST_P(DesksTest, VisibleOnAllDesksMoveWindowToDeskViaDragAndDrop) {
auto* controller = DesksController::Get();
auto* root = Shell::GetPrimaryRootWindow();
NewDesk();
const Desk* desk_1 = controller->GetDeskAtIndex(0);
const Desk* desk_2 = controller->GetDeskAtIndex(1);
auto window = CreateAppWindow(gfx::Rect(0, 0, 100, 100));
auto* widget = views::Widget::GetWidgetForNativeWindow(window.get());
widget->SetVisibleOnAllWorkspaces(true);
ASSERT_TRUE(desks_util::IsWindowVisibleOnAllWorkspaces(window.get()));
EXPECT_FALSE(controller->MoveWindowFromActiveDeskTo(
window.get(), const_cast<Desk*>(desk_2), root,
DesksMoveWindowFromActiveDeskSource::kDragAndDrop));
EXPECT_TRUE(desks_util::BelongsToActiveDesk(window.get()));
EXPECT_EQ(1u, controller->visible_on_all_desks_windows().size());
EXPECT_TRUE(desks_util::IsWindowVisibleOnAllWorkspaces(window.get()));
EXPECT_TRUE(base::Contains(desk_1->windows(), window.get()));
}
TEST_P(DesksTest, VisibleOnAllDesksMoveWindowToDeskViaShortcuts) {
auto* controller = DesksController::Get();
auto* root = Shell::GetPrimaryRootWindow();
NewDesk();
const Desk* desk_2 = controller->GetDeskAtIndex(1);
auto window = CreateAppWindow(gfx::Rect(0, 0, 100, 100));
auto* widget = views::Widget::GetWidgetForNativeWindow(window.get());
widget->SetVisibleOnAllWorkspaces(true);
ASSERT_TRUE(desks_util::IsWindowVisibleOnAllWorkspaces(window.get()));
EXPECT_TRUE(controller->MoveWindowFromActiveDeskTo(
window.get(), const_cast<Desk*>(desk_2), root,
DesksMoveWindowFromActiveDeskSource::kShortcut));
EXPECT_FALSE(desks_util::BelongsToActiveDesk(window.get()));
EXPECT_EQ(0u, controller->visible_on_all_desks_windows().size());
EXPECT_FALSE(desks_util::IsWindowVisibleOnAllWorkspaces(window.get()));
EXPECT_TRUE(base::Contains(desk_2->windows(), window.get()));
}
TEST_P(DesksTest, VisibleOnAllDesksMoveWindowToDeskViaContextMenu) {
auto* controller = DesksController::Get();
NewDesk();
const Desk* desk_2 = controller->GetDeskAtIndex(1);
auto window = CreateAppWindow(gfx::Rect(0, 0, 100, 100));
auto* widget = views::Widget::GetWidgetForNativeWindow(window.get());
widget->SetVisibleOnAllWorkspaces(true);
ASSERT_TRUE(desks_util::IsWindowVisibleOnAllWorkspaces(window.get()));
controller->SendToDeskAtIndex(window.get(), controller->GetDeskIndex(desk_2));
EXPECT_FALSE(desks_util::BelongsToActiveDesk(window.get()));
EXPECT_EQ(0u, controller->visible_on_all_desks_windows().size());
EXPECT_FALSE(desks_util::IsWindowVisibleOnAllWorkspaces(window.get()));
EXPECT_TRUE(base::Contains(desk_2->windows(), window.get()));
}
TEST_P(DesksTest, VisibleOnAllDesksWindowDestruction) {
auto* controller = DesksController::Get();
NewDesk();
const Desk* desk_1 = controller->GetDeskAtIndex(0);
auto* root = Shell::GetPrimaryRootWindow();
auto window = CreateAppWindow(gfx::Rect(0, 0, 100, 100));
auto* widget = views::Widget::GetWidgetForNativeWindow(window.get());
widget->SetVisibleOnAllWorkspaces(true);
ASSERT_TRUE(desks_util::IsWindowVisibleOnAllWorkspaces(window.get()));
EXPECT_EQ(1u, controller->visible_on_all_desks_windows().size());
EXPECT_EQ(1u, desk_1->GetDeskContainerForRoot(root)->children().size());
window.reset();
EXPECT_EQ(0u, controller->visible_on_all_desks_windows().size());
EXPECT_EQ(0u, desk_1->GetDeskContainerForRoot(root)->children().size());
}
TEST_P(DesksTest, VisibleOnAllDesksInactiveDesk) {
auto* controller = DesksController::Get();
auto window = CreateAppWindow(gfx::Rect(0, 0, 100, 100));
auto* widget = views::Widget::GetWidgetForNativeWindow(window.get());
NewDesk();
auto* desk1 = controller->GetDeskAtIndex(0);
auto* desk2 = controller->GetDeskAtIndex(1);
ActivateDesk(desk2);
ASSERT_FALSE(desk1->is_active());
ASSERT_TRUE(desk2->is_active());
ASSERT_THAT(desk1->windows(), ElementsAre(window.get()));
ASSERT_THAT(desk2->windows(), ElementsAre());
widget->SetVisibleOnAllWorkspaces(true);
EXPECT_THAT(desk1->windows(), ElementsAre());
EXPECT_THAT(desk2->windows(), ElementsAre(window.get()));
}
TEST_P(DesksTest, DesksBarExitAnimation) {
NewDesk();
gfx::ScopedAnimationDurationScaleMode animation(
gfx::ScopedAnimationDurationScaleMode::NON_ZERO_DURATION);
EnterOverview();
ExitOverview();
}
TEST_P(DesksTest, EnterOverviewWithCorrectDesksBarState) {
auto* controller = DesksController::Get();
ASSERT_EQ(1u, controller->desks().size());
EnterOverview();
auto* root_window = Shell::GetPrimaryRootWindow();
auto* desks_bar_view = GetOverviewGridForRoot(root_window)->desks_bar_view();
EXPECT_TRUE(desks_bar_view->IsZeroState());
EXPECT_TRUE(desks_bar_view->mini_views().empty());
LeftClickOn(desks_bar_view->new_desk_button());
ExitOverview();
EXPECT_EQ(2u, controller->desks().size());
EnterOverview();
desks_bar_view = GetOverviewGridForRoot(root_window)->desks_bar_view();
EXPECT_EQ(2u, desks_bar_view->mini_views().size());
EXPECT_FALSE(desks_bar_view->IsZeroState());
}
TEST_P(DesksTest, DesksBarZeroState) {
EnterOverview();
auto* root_window = Shell::GetPrimaryRootWindow();
auto* desks_bar_view = GetOverviewGridForRoot(root_window)->desks_bar_view();
ASSERT_TRUE(desks_bar_view->IsZeroState());
ASSERT_TRUE(desks_bar_view->mini_views().empty());
auto* default_desk_button = desks_bar_view->default_desk_button();
auto* new_desk_button = desks_bar_view->new_desk_button();
LeftClickOn(default_desk_button);
EXPECT_FALSE(desks_bar_view->IsZeroState());
EXPECT_EQ(1u, desks_bar_view->mini_views().size());
EXPECT_TRUE(desks_bar_view->mini_views()[0]->desk_name_view()->HasFocus());
EXPECT_FALSE(default_desk_button->GetVisible());
VerifyZeroStateNewDeskButtonVisibility(desks_bar_view, false);
ExitOverview();
EnterOverview();
desks_bar_view = GetOverviewGridForRoot(root_window)->desks_bar_view();
ASSERT_TRUE(desks_bar_view->IsZeroState());
default_desk_button = desks_bar_view->default_desk_button();
new_desk_button = desks_bar_view->new_desk_button();
LeftClickOn(new_desk_button);
EXPECT_FALSE(desks_bar_view->IsZeroState());
EXPECT_EQ(2u, desks_bar_view->mini_views().size());
EXPECT_TRUE(desks_bar_view->mini_views()[1]->desk_name_view()->HasFocus());
EXPECT_FALSE(default_desk_button->GetVisible());
VerifyZeroStateNewDeskButtonVisibility(desks_bar_view, false);
CloseDeskFromMiniView(desks_bar_view->mini_views()[0], GetEventGenerator());
EXPECT_FALSE(desks_bar_view->IsZeroState());
EXPECT_FALSE(default_desk_button->GetVisible());
VerifyZeroStateNewDeskButtonVisibility(desks_bar_view, false);
}
TEST_P(DesksTest, DesksBarButtonVisibility) {
auto* controller = DesksController::Get();
NewDesk();
ASSERT_EQ(2u, controller->desks().size());
auto* overview_controller = OverviewController::Get();
EnterOverview();
EXPECT_TRUE(overview_controller->InOverviewSession());
const auto* desks_bar_view =
GetOverviewGridForRoot(Shell::GetPrimaryRootWindow())->desks_bar_view();
ASSERT_TRUE(desks_bar_view);
ASSERT_FALSE(desks_bar_view->IsZeroState());
auto* default_desk_button = desks_bar_view->default_desk_button();
VerifyExpandedStateNewDeskButtonVisibility(desks_bar_view, true);
VerifyZeroStateNewDeskButtonVisibility(desks_bar_view, false);
EXPECT_FALSE(default_desk_button->GetVisible());
auto* mini_view = desks_bar_view->mini_views().front().get();
CloseDeskFromMiniView(mini_view, GetEventGenerator());
ASSERT_EQ(1u, controller->desks().size());
ASSERT_FALSE(desks_bar_view->IsZeroState());
EXPECT_EQ(1u, desks_bar_view->mini_views().size());
VerifyExpandedStateNewDeskButtonVisibility(desks_bar_view, true);
VerifyZeroStateNewDeskButtonVisibility(desks_bar_view, false);
EXPECT_FALSE(default_desk_button->GetVisible());
}
TEST_P(DesksTest, NewDeskButton) {
auto* controller = DesksController::Get();
EnterOverview();
auto* root_window = Shell::GetPrimaryRootWindow();
auto* desks_bar_view = GetOverviewGridForRoot(root_window)->desks_bar_view();
LeftClickOn(desks_bar_view->default_desk_button());
RunScheduledLayoutForAllOverviewDeskBars();
auto* new_desk_button = desks_bar_view->new_desk_button();
EXPECT_TRUE(new_desk_button->GetVisible());
EXPECT_TRUE(new_desk_button->GetEnabled());
for (size_t i = 1; i < desks_util::GetMaxNumberOfDesks(); i++) {
LeftClickOn(new_desk_button);
RunScheduledLayoutForAllOverviewDeskBars();
auto* mini_view = desks_bar_view->mini_views().back().get();
EXPECT_EQ(mini_view->size(), mini_view->GetVisibleBounds().size());
if (!base::i18n::IsRTL()) {
EXPECT_EQ(new_desk_button->size(),
new_desk_button->GetVisibleBounds().size());
}
TryScrollOverviewDeskBar(DeskBarScrollDirection::kRight);
RunScheduledLayoutForAllOverviewDeskBars();
}
EXPECT_FALSE(controller->CanCreateDesks());
EXPECT_FALSE(new_desk_button->GetEnabled());
ASSERT_EQ(controller->desks().size(), desks_util::GetMaxNumberOfDesks());
CloseDeskFromMiniView(desks_bar_view->mini_views().back(),
GetEventGenerator());
RunScheduledLayoutForAllOverviewDeskBars();
EXPECT_TRUE(controller->CanCreateDesks());
EXPECT_TRUE(new_desk_button->GetEnabled());
}
TEST_P(DesksTest, ZeroStateDeskButtonText) {
UpdateDisplay("1600x1200");
EnterOverview();
auto* root_window = Shell::GetPrimaryRootWindow();
auto* desks_bar_view = GetOverviewGridForRoot(root_window)->desks_bar_view();
ASSERT_TRUE(desks_bar_view->IsZeroState());
EXPECT_EQ(u"Desk 1", desks_bar_view->default_desk_button()->GetText());
LeftClickOn(desks_bar_view->default_desk_button());
EXPECT_TRUE(desks_bar_view->mini_views()[0]->desk_name_view()->HasFocus());
PressAndReleaseKey(ui::VKEY_T);
PressAndReleaseKey(ui::VKEY_E);
PressAndReleaseKey(ui::VKEY_S);
PressAndReleaseKey(ui::VKEY_T);
PressAndReleaseKey(ui::VKEY_RETURN);
ExitOverview();
EnterOverview();
desks_bar_view = GetOverviewGridForRoot(root_window)->desks_bar_view();
EXPECT_TRUE(desks_bar_view->IsZeroState());
EXPECT_EQ(u"test", desks_bar_view->default_desk_button()->GetText());
LeftClickOn(desks_bar_view->new_desk_button());
EXPECT_FALSE(desks_bar_view->IsZeroState());
PressAndReleaseKey(ui::VKEY_RETURN);
EXPECT_EQ(u"Desk 2", DesksController::Get()->GetDeskAtIndex(1)->name());
CloseDeskFromMiniView(desks_bar_view->mini_views()[0], GetEventGenerator());
ExitOverview();
EnterOverview();
desks_bar_view = GetOverviewGridForRoot(root_window)->desks_bar_view();
EXPECT_TRUE(desks_bar_view->IsZeroState());
EXPECT_EQ(u"Desk 1", desks_bar_view->default_desk_button()->GetText());
LeftClickOn(desks_bar_view->default_desk_button());
for (size_t i = 0; i < DeskTextfield::kMaxLength + 5; i++) {
PressAndReleaseKey(ui::VKEY_A);
}
PressAndReleaseKey(ui::VKEY_RETURN);
ExitOverview();
EnterOverview();
desks_bar_view = GetOverviewGridForRoot(root_window)->desks_bar_view();
auto* default_desk_button = desks_bar_view->default_desk_button();
std::u16string_view desk_button_text = default_desk_button->GetText();
std::u16string expected_desk_name(DeskTextfield::kMaxLength, L'a');
EXPECT_EQ(expected_desk_name,
DesksController::Get()->GetDeskAtIndex(0)->name());
EXPECT_NE(expected_desk_name, desk_button_text);
EXPECT_TRUE(base::StartsWith(base::UTF16ToUTF8(desk_button_text), "aaa",
base::CompareCase::SENSITIVE));
EXPECT_FALSE(base::EndsWith(base::UTF16ToUTF8(desk_button_text), "aaa",
base::CompareCase::SENSITIVE));
}
TEST_P(DesksTest, ReorderDesksByMouse) {
auto* desks_controller = DesksController::Get();
EnterOverview();
EXPECT_TRUE(OverviewController::Get()->InOverviewSession());
auto* root_window = Shell::GetPrimaryRootWindow();
const auto* desks_bar_view =
GetOverviewGridForRoot(root_window)->desks_bar_view();
auto* event_generator = GetEventGenerator();
NewDesk();
NewDesk();
std::vector<raw_ptr<DeskMiniView, VectorExperimental>> mini_views =
desks_bar_view->mini_views();
DeskMiniView* mini_view_0 = mini_views[0];
Desk* desk_0 = mini_view_0->desk();
DeskMiniView* mini_view_1 = mini_views[1];
Desk* desk_1 = mini_view_1->desk();
DeskMiniView* mini_view_2 = mini_views[2];
Desk* desk_2 = mini_view_2->desk();
desk_0->SetName(u"0", true);
desk_1->SetName(u"1", true);
desk_2->SetName(u"2", true);
desks_restore_util::UpdatePrimaryUserDeskNamesPrefs();
auto* prefs = Shell::Get()->session_controller()->GetPrimaryUserPrefService();
EXPECT_THAT(GetDeskRestoreNames(prefs), ElementsAre("0", "1", "2"));
StartDragDeskPreview(mini_view_1, event_generator);
EXPECT_TRUE(desks_bar_view->IsDraggingDesk());
event_generator->ReleaseLeftButton();
RunScheduledLayoutForAllOverviewDeskBars();
StartDragDeskPreview(mini_view_1, event_generator);
EXPECT_TRUE(desks_bar_view->IsDraggingDesk());
gfx::Point desk_center_2 =
mini_view_2->GetPreviewBoundsInScreen().CenterPoint();
event_generator->MoveMouseTo(desk_center_2);
RunScheduledLayoutForAllOverviewDeskBars();
EXPECT_EQ(0, desks_controller->GetDeskIndex(desk_0));
EXPECT_EQ(1, desks_controller->GetDeskIndex(desk_2));
EXPECT_EQ(2, desks_controller->GetDeskIndex(desk_1));
EXPECT_THAT(GetDeskRestoreNames(prefs), ElementsAre("0", "2", "1"));
gfx::Point desk_center_0 =
mini_view_0->GetPreviewBoundsInScreen().CenterPoint();
event_generator->MoveMouseTo(desk_center_0);
RunScheduledLayoutForAllOverviewDeskBars();
EXPECT_EQ(0, desks_controller->GetDeskIndex(desk_1));
EXPECT_EQ(1, desks_controller->GetDeskIndex(desk_0));
EXPECT_EQ(2, desks_controller->GetDeskIndex(desk_2));
EXPECT_THAT(GetDeskRestoreNames(prefs), ElementsAre("1", "0", "2"));
event_generator->ReleaseLeftButton();
RunScheduledLayoutForAllOverviewDeskBars();
}
TEST_P(DesksTest, ReorderDesksByGesture) {
auto* desks_controller = DesksController::Get();
EnterOverview();
EXPECT_TRUE(OverviewController::Get()->InOverviewSession());
auto* root_window = Shell::GetPrimaryRootWindow();
const auto* desks_bar_view =
GetOverviewGridForRoot(root_window)->desks_bar_view();
auto* event_generator = GetEventGenerator();
NewDesk();
NewDesk();
RunScheduledLayoutForAllOverviewDeskBars();
std::vector<raw_ptr<DeskMiniView, VectorExperimental>> mini_views =
desks_bar_view->mini_views();
DeskMiniView* mini_view_0 = mini_views[0];
Desk* desk_0 = mini_view_0->desk();
DeskMiniView* mini_view_1 = mini_views[1];
Desk* desk_1 = mini_view_1->desk();
DeskMiniView* mini_view_2 = mini_views[2];
Desk* desk_2 = mini_view_2->desk();
desk_0->SetName(u"0", true);
desk_1->SetName(u"1", true);
desk_2->SetName(u"2", true);
desks_restore_util::UpdatePrimaryUserDeskNamesPrefs();
auto* prefs = Shell::Get()->session_controller()->GetPrimaryUserPrefService();
EXPECT_THAT(GetDeskRestoreNames(prefs), ElementsAre("0", "1", "2"));
LongTapOnDeskPreview(mini_view_1, event_generator);
EXPECT_TRUE(desks_bar_view->IsDraggingDesk());
event_generator->ReleaseTouch();
event_generator->GestureTapDownAndUp(
mini_view_1->desk_preview()->GetBoundsInScreen().CenterPoint());
base::RunLoop().RunUntilIdle();
LongTapOnDeskPreview(mini_view_1, event_generator);
EXPECT_TRUE(desks_bar_view->IsDraggingDesk());
gfx::Point desk_center_2 =
mini_view_2->GetPreviewBoundsInScreen().CenterPoint();
event_generator->MoveTouchBy(10, 0);
event_generator->MoveTouch(desk_center_2);
RunScheduledLayoutForAllOverviewDeskBars();
EXPECT_EQ(0, desks_controller->GetDeskIndex(desk_0));
EXPECT_EQ(1, desks_controller->GetDeskIndex(desk_2));
EXPECT_EQ(2, desks_controller->GetDeskIndex(desk_1));
EXPECT_THAT(GetDeskRestoreNames(prefs), ElementsAre("0", "2", "1"));
gfx::Point desk_center_0 =
mini_view_0->GetPreviewBoundsInScreen().CenterPoint();
event_generator->MoveTouch(desk_center_0);
EXPECT_EQ(0, desks_controller->GetDeskIndex(desk_1));
EXPECT_EQ(1, desks_controller->GetDeskIndex(desk_0));
EXPECT_EQ(2, desks_controller->GetDeskIndex(desk_2));
EXPECT_THAT(GetDeskRestoreNames(prefs), ElementsAre("1", "0", "2"));
event_generator->ReleaseTouch();
}
TEST_P(DesksTest, ReorderDesksByKeyboard) {
auto* desks_controller = DesksController::Get();
auto* overview_controller = OverviewController::Get();
EnterOverview();
EXPECT_TRUE(overview_controller->InOverviewSession());
auto* root_window = Shell::GetPrimaryRootWindow();
auto* overview_grid = GetOverviewGridForRoot(root_window);
const auto* desks_bar_view = overview_grid->desks_bar_view();
auto* event_generator = GetEventGenerator();
NewDesk();
NewDesk();
overview_grid->CommitNameChanges();
std::vector<raw_ptr<DeskMiniView, VectorExperimental>> mini_views =
desks_bar_view->mini_views();
DeskMiniView* mini_view_0 = mini_views[0];
Desk* desk_0 = mini_view_0->desk();
DeskMiniView* mini_view_1 = mini_views[1];
Desk* desk_1 = mini_view_1->desk();
DeskMiniView* mini_view_2 = mini_views[2];
Desk* desk_2 = mini_view_2->desk();
desk_0->SetName(u"0", true);
desk_1->SetName(u"1", true);
desk_2->SetName(u"2", true);
desks_restore_util::UpdatePrimaryUserDeskNamesPrefs();
auto* prefs = Shell::Get()->session_controller()->GetPrimaryUserPrefService();
EXPECT_THAT(GetDeskRestoreNames(prefs), ElementsAre("0", "1", "2"));
mini_view_1->desk_preview()->RequestFocus();
event_generator->PressKey(ui::VKEY_RIGHT, ui::EF_CONTROL_DOWN);
EXPECT_EQ(0, desks_controller->GetDeskIndex(desk_0));
EXPECT_EQ(1, desks_controller->GetDeskIndex(desk_2));
EXPECT_EQ(2, desks_controller->GetDeskIndex(desk_1));
EXPECT_THAT(GetDeskRestoreNames(prefs), ElementsAre("0", "2", "1"));
event_generator->PressKey(ui::VKEY_RIGHT, ui::EF_CONTROL_DOWN);
EXPECT_EQ(0, desks_controller->GetDeskIndex(desk_0));
EXPECT_EQ(1, desks_controller->GetDeskIndex(desk_2));
EXPECT_EQ(2, desks_controller->GetDeskIndex(desk_1));
EXPECT_THAT(GetDeskRestoreNames(prefs), ElementsAre("0", "2", "1"));
event_generator->PressKey(ui::VKEY_LEFT, ui::EF_CONTROL_DOWN);
event_generator->PressKey(ui::VKEY_LEFT, ui::EF_CONTROL_DOWN);
EXPECT_EQ(0, desks_controller->GetDeskIndex(desk_1));
EXPECT_EQ(1, desks_controller->GetDeskIndex(desk_0));
EXPECT_EQ(2, desks_controller->GetDeskIndex(desk_2));
EXPECT_THAT(GetDeskRestoreNames(prefs), ElementsAre("1", "0", "2"));
event_generator->PressKey(ui::VKEY_LEFT, ui::EF_CONTROL_DOWN);
EXPECT_EQ(0, desks_controller->GetDeskIndex(desk_1));
EXPECT_EQ(1, desks_controller->GetDeskIndex(desk_0));
EXPECT_EQ(2, desks_controller->GetDeskIndex(desk_2));
EXPECT_THAT(GetDeskRestoreNames(prefs), ElementsAre("1", "0", "2"));
}
TEST_P(DesksTest, ReorderDesksInRTLMode) {
base::i18n::ScopedRTLForTesting scoped_rtl(true);
EXPECT_TRUE(base::i18n::IsRTL());
auto* desks_controller = DesksController::Get();
auto* overview_controller = OverviewController::Get();
EnterOverview();
EXPECT_TRUE(overview_controller->InOverviewSession());
auto* root_window = Shell::GetPrimaryRootWindow();
const auto* desks_bar_view =
GetOverviewGridForRoot(root_window)->desks_bar_view();
auto* event_generator = GetEventGenerator();
NewDesk();
NewDesk();
std::vector<raw_ptr<DeskMiniView, VectorExperimental>> mini_views =
desks_bar_view->mini_views();
DeskMiniView* mini_view_0 = mini_views[0];
Desk* desk_0 = mini_view_0->desk();
DeskMiniView* mini_view_1 = mini_views[1];
Desk* desk_1 = mini_view_1->desk();
DeskMiniView* mini_view_2 = mini_views[2];
Desk* desk_2 = mini_view_2->desk();
desk_0->SetName(u"0", true);
desk_1->SetName(u"1", true);
desk_2->SetName(u"2", true);
desks_restore_util::UpdatePrimaryUserDeskNamesPrefs();
auto* prefs = Shell::Get()->session_controller()->GetPrimaryUserPrefService();
EXPECT_THAT(GetDeskRestoreNames(prefs), ElementsAre("0", "1", "2"));
StartDragDeskPreview(mini_view_1, event_generator);
EXPECT_TRUE(desks_bar_view->IsDraggingDesk());
gfx::Point desk_center_2 =
mini_view_2->GetPreviewBoundsInScreen().CenterPoint();
event_generator->MoveMouseTo(desk_center_2);
EXPECT_EQ(0, desks_controller->GetDeskIndex(desk_0));
EXPECT_EQ(1, desks_controller->GetDeskIndex(desk_2));
EXPECT_EQ(2, desks_controller->GetDeskIndex(desk_1));
EXPECT_THAT(GetDeskRestoreNames(prefs), ElementsAre("0", "2", "1"));
event_generator->ReleaseLeftButton();
LongTapOnDeskPreview(mini_view_1, event_generator);
EXPECT_TRUE(desks_bar_view->IsDraggingDesk());
gfx::Point desk_center_0 =
mini_view_0->GetPreviewBoundsInScreen().CenterPoint();
event_generator->MoveTouchBy(-10, 0);
event_generator->MoveTouch(desk_center_0);
EXPECT_EQ(0, desks_controller->GetDeskIndex(desk_1));
EXPECT_EQ(1, desks_controller->GetDeskIndex(desk_0));
EXPECT_EQ(2, desks_controller->GetDeskIndex(desk_2));
EXPECT_THAT(GetDeskRestoreNames(prefs), ElementsAre("1", "0", "2"));
event_generator->ReleaseTouch();
mini_view_0->desk_preview()->RequestFocus();
event_generator->PressKey(ui::VKEY_RIGHT, ui::EF_CONTROL_DOWN);
EXPECT_EQ(0, desks_controller->GetDeskIndex(desk_1));
EXPECT_EQ(1, desks_controller->GetDeskIndex(desk_2));
EXPECT_EQ(2, desks_controller->GetDeskIndex(desk_0));
EXPECT_THAT(GetDeskRestoreNames(prefs), ElementsAre("1", "2", "0"));
}
TEST_P(DesksTest, ScrollBarByDraggedDesk) {
const int scroll_timeout_ms = 20;
base::AutoReset<base::TimeDelta> auto_reset =
DesksTestApi::SetScrollTimeInterval(
base::Milliseconds(scroll_timeout_ms));
UpdateDisplay("800x150");
const size_t max_desks_size = desks_util::GetMaxNumberOfDesks();
for (size_t i = 1; i < max_desks_size; i++) {
NewDesk();
}
auto* desks_controller = DesksController::Get();
EXPECT_EQ(desks_controller->desks().size(), max_desks_size);
EnterOverview();
EXPECT_TRUE(OverviewController::Get()->InOverviewSession());
auto* desks_bar =
GetOverviewGridForRoot(Shell::GetPrimaryRootWindow())->desks_bar_view();
views::ScrollView* scroll_view =
DesksTestApi::GetDeskBarScrollView(DeskBarViewBase::Type::kOverview);
ASSERT_TRUE(scroll_view);
const int page_size = scroll_view->width();
auto mini_views = desks_bar->mini_views();
const int mini_view_width = mini_views[0]->bounds().width();
int desks_in_one_page = page_size / mini_view_width;
float fractional_page = static_cast<float>(page_size % mini_view_width) /
static_cast<float>(mini_view_width);
if (fractional_page > 0.5) {
desks_in_one_page++;
}
int current_index = 0;
ScrollArrowButton* left_button = DesksTestApi::GetDeskBarLeftScrollButton(
DeskBarViewBase::Type::kOverview);
ASSERT_TRUE(left_button);
ScrollArrowButton* right_button = DesksTestApi::GetDeskBarRightScrollButton(
DeskBarViewBase::Type::kOverview);
ASSERT_TRUE(right_button);
EXPECT_FALSE(left_button->GetVisible());
EXPECT_TRUE(right_button->GetVisible());
auto* event_generator = GetEventGenerator();
DeskMiniView* mini_view_0 = mini_views[0];
Desk* desk_0 = mini_view_0->desk();
const int focus_ring_width_and_padding = 4;
StartDragDeskPreview(mini_view_0, event_generator);
EXPECT_TRUE(desks_bar->IsDraggingDesk());
event_generator->MoveMouseTo(right_button->GetBoundsInScreen().CenterPoint());
RunScheduledLayoutForAllOverviewDeskBars();
current_index += desks_in_one_page;
EXPECT_EQ(scroll_view->GetVisibleRect().x() + focus_ring_width_and_padding,
mini_views[current_index]->bounds().x());
EXPECT_TRUE(left_button->GetVisible());
EXPECT_TRUE(right_button->GetVisible());
WaitForMilliseconds(scroll_timeout_ms);
current_index += desks_in_one_page;
if (!features::Is16DesksEnabled()) {
EXPECT_EQ(
scroll_view->GetVisibleRect().right() - focus_ring_width_and_padding,
desks_bar->new_desk_button()->bounds().right());
} else {
EXPECT_EQ(scroll_view->GetVisibleRect().x() + focus_ring_width_and_padding,
mini_views[current_index]->bounds().x());
}
EXPECT_EQ(0, desks_controller->GetDeskIndex(desk_0));
WaitForMilliseconds(GetParam().use_16_desks ? 10 * scroll_timeout_ms
: scroll_timeout_ms);
EXPECT_EQ(scroll_view->GetVisibleRect().x(),
scroll_view->contents()->width() - page_size);
EXPECT_TRUE(left_button->GetVisible());
EXPECT_FALSE(right_button->GetVisible());
event_generator->MoveMouseTo(
mini_views[max_desks_size - 1]->GetBoundsInScreen().CenterPoint());
RunScheduledLayoutForAllOverviewDeskBars();
const int max_index = static_cast<int>(max_desks_size) - 1;
EXPECT_EQ(max_index, desks_controller->GetDeskIndex(desk_0));
event_generator->ReleaseLeftButton();
RunScheduledLayoutForAllOverviewDeskBars();
current_index = max_desks_size - 1;
mini_views = desks_bar->mini_views();
StartDragDeskPreview(mini_views[max_desks_size - 1], event_generator);
event_generator->MoveMouseTo(left_button->GetBoundsInScreen().CenterPoint());
RunScheduledLayoutForAllOverviewDeskBars();
current_index -= (desks_in_one_page + 1);
EXPECT_EQ(scroll_view->GetVisibleRect().x() + focus_ring_width_and_padding,
mini_views[current_index]->bounds().x());
WaitForMilliseconds(scroll_timeout_ms);
current_index -= desks_in_one_page;
EXPECT_EQ(scroll_view->GetVisibleRect().x() + focus_ring_width_and_padding,
mini_views[current_index]->bounds().x());
EXPECT_EQ(max_index, desks_controller->GetDeskIndex(desk_0));
event_generator->ReleaseLeftButton();
RunScheduledLayoutForAllOverviewDeskBars();
WaitForMilliseconds(100);
gfx::Rect bounds_0 = mini_view_0->bounds();
gfx::Rect bounds_visible = scroll_view->GetVisibleRect();
EXPECT_LE(bounds_visible.x(), bounds_0.x());
EXPECT_GE(bounds_visible.right(), bounds_0.right());
}
TEST_P(DesksTest, ClickTargetLocationOfDroppedDesk) {
EnterOverview();
ASSERT_TRUE(OverviewController::Get()->InOverviewSession());
auto* overview_grid = GetOverviewGridForRoot(Shell::GetPrimaryRootWindow());
DeskBarViewBase* desk_bar_view = overview_grid->desks_bar_view();
NewDesk();
DeskMiniView* mini_view = desk_bar_view->mini_views()[1];
auto* event_generator = GetEventGenerator();
StartDragDeskPreview(mini_view, event_generator);
EXPECT_TRUE(desk_bar_view->IsDraggingDesk());
event_generator->MoveMouseBy(0, desk_bar_view->height());
gfx::ScopedAnimationDurationScaleMode normal_anim(
gfx::ScopedAnimationDurationScaleMode::NORMAL_DURATION);
event_generator->ReleaseLeftButton();
EXPECT_TRUE(desk_bar_view->IsDraggingDesk());
DeskSwitchAnimationWaiter waiter;
LeftClickOn(mini_view);
DesksTestApi::WaitForDeskBarUiUpdate(desk_bar_view);
waiter.Wait();
}
TEST_P(DesksTest, DragNewDeskWhileSnappingBack) {
EnterOverview();
ASSERT_TRUE(OverviewController::Get()->InOverviewSession());
auto* overview_grid = GetOverviewGridForRoot(Shell::GetPrimaryRootWindow());
const auto* desks_bar_view = overview_grid->desks_bar_view();
NewDesk();
DeskMiniView* mini_view_1 = desks_bar_view->mini_views()[0];
DeskMiniView* mini_view_2 = desks_bar_view->mini_views()[1];
auto* event_generator = GetEventGenerator();
StartDragDeskPreview(mini_view_2, event_generator);
EXPECT_EQ(DesksTestApi::GetDeskBarDragView(DeskBarViewBase::Type::kOverview),
mini_view_2);
event_generator->MoveMouseBy(0, desks_bar_view->height());
gfx::ScopedAnimationDurationScaleMode normal_anim(
gfx::ScopedAnimationDurationScaleMode::NORMAL_DURATION);
event_generator->ReleaseLeftButton();
EXPECT_EQ(DesksTestApi::GetDeskBarDragView(DeskBarViewBase::Type::kOverview),
mini_view_2);
StartDragDeskPreview(mini_view_1, event_generator);
EXPECT_EQ(DesksTestApi::GetDeskBarDragView(DeskBarViewBase::Type::kOverview),
mini_view_1);
}
TEST_P(DesksTest, RemoveDeskWhileDragging) {
EnterOverview();
EXPECT_TRUE(OverviewController::Get()->InOverviewSession());
const auto* desks_bar_view =
GetOverviewGridForRoot(Shell::GetPrimaryRootWindow())->desks_bar_view();
auto* event_generator = GetEventGenerator();
NewDesk();
NewDesk();
const std::vector<raw_ptr<DeskMiniView, VectorExperimental>>& mini_views =
desks_bar_view->mini_views();
DeskMiniView* mini_view_0 = mini_views[0];
DeskMiniView* mini_view_1 = mini_views[1];
DeskMiniView* mini_view_2 = mini_views[2];
StartDragDeskPreview(mini_view_0, event_generator);
EXPECT_TRUE(desks_bar_view->IsDraggingDesk());
RemoveDesk(mini_view_0->desk());
EXPECT_FALSE(desks_bar_view->IsDraggingDesk());
event_generator->ReleaseLeftButton();
EXPECT_EQ(2u, mini_views.size());
StartDragDeskPreview(mini_view_1, event_generator);
EXPECT_TRUE(desks_bar_view->IsDraggingDesk());
RemoveDesk(mini_view_2->desk());
EXPECT_TRUE(desks_bar_view->IsDraggingDesk());
ExitOverview();
}
class LayerAnimationWaiter : public ui::LayerAnimationObserver {
public:
explicit LayerAnimationWaiter(ui::LayerAnimator* animator)
: animator_(animator) {
animator_->AddObserver(this);
}
void OnLayerAnimationEnded(ui::LayerAnimationSequence* sequence) override {
OnAnimationCompleted();
}
void OnLayerAnimationAborted(ui::LayerAnimationSequence* sequence) override {
OnAnimationCompleted();
}
void OnLayerAnimationScheduled(
ui::LayerAnimationSequence* sequence) override {}
void Wait() { run_loop_.Run(); }
private:
void OnAnimationCompleted() {
if (animator_->is_animating() == false) {
animator_->RemoveObserver(this);
run_loop_.Quit();
}
}
raw_ptr<ui::LayerAnimator> animator_;
base::RunLoop run_loop_;
};
TEST_P(DesksTest, DragMiniViewWhileRemoving) {
NewDesk();
NewDesk();
EnterOverview();
EXPECT_TRUE(OverviewController::Get()->InOverviewSession());
const auto* desks_bar_view =
GetOverviewGridForRoot(Shell::GetPrimaryRootWindow())->desks_bar_view();
auto* event_generator = GetEventGenerator();
auto* mini_view = desks_bar_view->mini_views().back().get();
const gfx::Point desk_preview_center =
mini_view->GetPreviewBoundsInScreen().CenterPoint();
LayerAnimationWaiter animation_waiter(mini_view->layer()->GetAnimator());
{
gfx::ScopedAnimationDurationScaleMode animation_scale(
gfx::ScopedAnimationDurationScaleMode::NORMAL_DURATION);
CloseDeskFromMiniView(mini_view, event_generator);
event_generator->set_current_screen_location(desk_preview_center);
event_generator->PressLeftButton();
event_generator->MoveMouseBy(0, 50);
EXPECT_FALSE(desks_bar_view->IsDraggingDesk());
}
animation_waiter.Wait();
}
TEST_P(DesksTest, FastDeskSwitches) {
CreateTestWindow();
CreateTestWindow();
for (int i = 0; i < 3; ++i) {
NewDesk();
CreateTestWindow();
CreateTestWindow();
}
auto* desks_controller = DesksController::Get();
ASSERT_EQ(4u, desks_controller->desks().size());
desks_controller->ActivateDesk(desks_controller->GetDeskAtIndex(3),
DesksSwitchSource::kUserSwitch);
gfx::ScopedAnimationDurationScaleMode normal_anim(
gfx::ScopedAnimationDurationScaleMode::NORMAL_DURATION);
desks_controller->ActivateAdjacentDesk(
true, DesksSwitchSource::kDeskSwitchShortcut);
desks_controller->ActivateAdjacentDesk(
true, DesksSwitchSource::kDeskSwitchShortcut);
desks_controller->ActivateAdjacentDesk(
true, DesksSwitchSource::kDeskSwitchShortcut);
DeskSwitchAnimationWaiter waiter;
waiter.Wait();
std::vector<aura::Window*> desk_containers =
desks_util::GetDesksContainers(Shell::GetPrimaryRootWindow());
ASSERT_EQ(desks_util::GetMaxNumberOfDesks(), desk_containers.size());
EXPECT_TRUE(desk_containers[0]->IsVisible());
EXPECT_EQ(1.f, desk_containers[0]->layer()->opacity());
for (size_t i = 1; i < desk_containers.size(); ++i) {
SCOPED_TRACE(base::StringPrintf("Desk #%lu", i + 1));
EXPECT_FALSE(desk_containers[i]->IsVisible());
EXPECT_EQ(1.f, desk_containers[i]->layer()->opacity());
}
}
TEST_P(DesksTest, NameNudgesTabletMode) {
TabletModeControllerTestApi().EnterTabletMode();
NewDesk();
ASSERT_EQ(2u, DesksController::Get()->desks().size());
EnterOverview();
ASSERT_TRUE(OverviewController::Get()->InOverviewSession());
ui::DeviceDataManagerTestApi().SetKeyboardDevices(
std::vector<ui::KeyboardDevice>{
{1, ui::INPUT_DEVICE_INTERNAL, "internal keyboard"},
{2, ui::INPUT_DEVICE_USB, "external keyboard"}});
auto* device_data_manager = ui::DeviceDataManager::GetInstance();
auto keyboard_devices = device_data_manager->GetKeyboardDevices();
ASSERT_EQ(2u, keyboard_devices.size());
const auto* desks_bar_view =
GetOverviewGridForRoot(Shell::GetPrimaryRootWindow())->desks_bar_view();
GestureTapOn(desks_bar_view->new_desk_button());
RunScheduledLayoutForAllOverviewDeskBars();
EXPECT_FALSE(keyboard::KeyboardUIController::Get()->IsKeyboardVisible());
EXPECT_EQ(3u, desks_bar_view->mini_views().size());
auto* desk_name_view = desks_bar_view->mini_views()[2]->desk_name_view();
EXPECT_TRUE(desk_name_view->HasFocus());
EXPECT_EQ(std::u16string(), desk_name_view->GetText());
ui::DeviceDataManagerTestApi().SetKeyboardDevices(
std::vector<ui::KeyboardDevice>{
{1, ui::INPUT_DEVICE_INTERNAL, "internal keyboard"},
});
keyboard_devices = device_data_manager->GetKeyboardDevices();
ASSERT_EQ(1u, keyboard_devices.size());
ui::DeviceDataManagerTestApi().SetKeyboardDevices({});
GestureTapOn(desks_bar_view->new_desk_button());
RunScheduledLayoutForAllOverviewDeskBars();
ASSERT_TRUE(keyboard::test::WaitUntilShown());
EXPECT_TRUE(keyboard::KeyboardUIController::Get()->IsKeyboardVisible());
EXPECT_EQ(4u, desks_bar_view->mini_views().size());
desk_name_view = desks_bar_view->mini_views()[3]->desk_name_view();
EXPECT_TRUE(desk_name_view->HasFocus());
EXPECT_EQ(std::u16string(), desk_name_view->GetText());
}
TEST_P(DesksTest, TestCustomDeskNameMetricsRecording) {
enum class UpdateSource {
kDeskRenamed,
kDeskAdded,
kDeskRemoved,
};
struct {
const std::string scope_trace;
const UpdateSource update_source;
const int expected_number_of_custom_desks;
const int expected_percentage_of_custom_desks;
const int expected_custom_name_change_true_hits;
const int expected_custom_name_change_false_hits;
} kTestCases[] = {
{"Rename a desk", UpdateSource::kDeskRenamed, 1, 50, 1, 1},
{"Add a desk", UpdateSource::kDeskAdded, 1, 33, 1, 2},
{"Remove a desk", UpdateSource::kDeskRemoved, 1, 50, 1, 2},
};
base::HistogramTester histogram_tester;
NewDesk();
int number_of_updates = 1;
histogram_tester.ExpectTotalCount(kNumberOfCustomNamesHistogramName,
number_of_updates);
histogram_tester.ExpectTotalCount(kPercentageOfCustomNamesHistogramName,
number_of_updates);
histogram_tester.ExpectTotalCount(kCustomNameCreatedHistogramName,
number_of_updates);
const auto& desks = DesksController::Get()->desks();
for (const auto& test_case : kTestCases) {
SCOPED_TRACE(test_case.scope_trace);
switch (test_case.update_source) {
case UpdateSource::kDeskRenamed:
desks[0]->SetName(u"Hello", true);
break;
case UpdateSource::kDeskAdded:
NewDesk();
break;
case UpdateSource::kDeskRemoved:
RemoveDesk(desks.back().get());
break;
}
++number_of_updates;
histogram_tester.ExpectTotalCount(kNumberOfCustomNamesHistogramName,
number_of_updates);
histogram_tester.ExpectTotalCount(kPercentageOfCustomNamesHistogramName,
number_of_updates);
EXPECT_NE(0, histogram_tester.GetBucketCount(
kNumberOfCustomNamesHistogramName,
test_case.expected_number_of_custom_desks));
EXPECT_NE(0, histogram_tester.GetBucketCount(
kPercentageOfCustomNamesHistogramName,
test_case.expected_percentage_of_custom_desks));
EXPECT_EQ(
test_case.expected_custom_name_change_true_hits,
histogram_tester.GetBucketCount(kCustomNameCreatedHistogramName, true));
EXPECT_EQ(test_case.expected_custom_name_change_false_hits,
histogram_tester.GetBucketCount(kCustomNameCreatedHistogramName,
false));
}
}
TEST_P(DesksTest, EnterOverviewAndAddDeskInGuestMode) {
SimulateGuestLogin();
EnterOverview();
auto* overview_controller = OverviewController::Get();
ASSERT_TRUE(overview_controller->InOverviewSession());
auto* overview_grid = GetOverviewGridForRoot(Shell::GetPrimaryRootWindow());
const auto* desks_bar_view = overview_grid->desks_bar_view();
auto* new_desk_button = desks_bar_view->new_desk_button();
LeftClickOn(new_desk_button);
ASSERT_FALSE(desks_bar_view->IsZeroState());
new_desk_button = desks_bar_view->new_desk_button();
LeftClickOn(new_desk_button);
EXPECT_EQ(3u, DesksController::Get()->desks().size());
}
class DesksMockTimeTest : public DesksTest {
public:
DesksMockTimeTest()
: DesksTest(base::test::TaskEnvironment::TimeSource::MOCK_TIME) {}
DesksMockTimeTest(const DesksMockTimeTest&) = delete;
DesksMockTimeTest& operator=(const DesksMockTimeTest&) = delete;
~DesksMockTimeTest() override = default;
void SetUp() override {
Desk::SetWeeklyActiveDesks(0);
DesksTest::SetUp();
}
};
TEST_P(DesksMockTimeTest, WeeklyActiveDesks) {
constexpr char kWeeklyActiveDesksHistogram[] = "Ash.Desks.WeeklyActiveDesks";
base::HistogramTester histogram_tester;
NewDesk();
NewDesk();
NewDesk();
auto* controller = DesksController::Get();
ASSERT_EQ(4u, controller->desks().size());
const Desk* desk_1 = controller->GetDeskAtIndex(0);
const Desk* desk_2 = controller->GetDeskAtIndex(1);
Desk* desk_3 = controller->GetDeskAtIndex(2);
Desk* desk_4 = controller->GetDeskAtIndex(3);
task_environment()->AdvanceClock(base::Days(7));
task_environment()->RunUntilIdle();
histogram_tester.ExpectBucketCount(kWeeklyActiveDesksHistogram, 4, 1);
EXPECT_EQ(1u,
histogram_tester.GetAllSamples(kWeeklyActiveDesksHistogram).size());
EXPECT_EQ(1, Desk::GetWeeklyActiveDesks());
ActivateDesk(desk_2);
ActivateDesk(desk_1);
task_environment()->AdvanceClock(base::Days(7));
task_environment()->RunUntilIdle();
histogram_tester.ExpectBucketCount(kWeeklyActiveDesksHistogram, 1, 1);
EXPECT_EQ(2u,
histogram_tester.GetAllSamples(kWeeklyActiveDesksHistogram).size());
EXPECT_EQ(1, Desk::GetWeeklyActiveDesks());
ActivateDesk(desk_2);
task_environment()->FastForwardBy(base::Seconds(5));
ActivateDesk(desk_1);
task_environment()->FastForwardBy(base::Seconds(5));
ActivateDesk(desk_2);
task_environment()->AdvanceClock(base::Days(7));
task_environment()->RunUntilIdle();
histogram_tester.ExpectBucketCount(kWeeklyActiveDesksHistogram, 2, 1);
EXPECT_EQ(3u,
histogram_tester.GetAllSamples(kWeeklyActiveDesksHistogram).size());
EXPECT_EQ(1, Desk::GetWeeklyActiveDesks());
desk_3->SetName(u"foo", true);
desk_3->SetName(u"bar", true);
auto win1 = CreateAppWindow();
auto win2 = CreateAppWindow();
controller->MoveWindowFromActiveDeskTo(
win1.get(), desk_4, win1->GetRootWindow(),
DesksMoveWindowFromActiveDeskSource::kSendToDesk);
controller->MoveWindowFromActiveDeskTo(
win2.get(), desk_4, win2->GetRootWindow(),
DesksMoveWindowFromActiveDeskSource::kSendToDesk);
task_environment()->AdvanceClock(base::Days(7));
task_environment()->RunUntilIdle();
histogram_tester.ExpectBucketCount(kWeeklyActiveDesksHistogram, 3, 1);
EXPECT_EQ(4u,
histogram_tester.GetAllSamples(kWeeklyActiveDesksHistogram).size());
EXPECT_EQ(1, Desk::GetWeeklyActiveDesks());
const int number_of_one_bucket_entries =
histogram_tester.GetBucketCount(kWeeklyActiveDesksHistogram, 1);
task_environment()->AdvanceClock(base::Days(6));
task_environment()->RunUntilIdle();
histogram_tester.ExpectBucketCount(kWeeklyActiveDesksHistogram, 1,
number_of_one_bucket_entries);
task_environment()->AdvanceClock(base::Days(1));
task_environment()->RunUntilIdle();
histogram_tester.ExpectBucketCount(kWeeklyActiveDesksHistogram, 1,
number_of_one_bucket_entries + 1);
}
class WindowHolder : public aura::WindowObserver {
public:
explicit WindowHolder(std::unique_ptr<aura::Window> window)
: window_(std::move(window)) {
DCHECK(window_);
window_->AddObserver(this);
}
WindowHolder(const WindowHolder&) = delete;
WindowHolder& operator=(const WindowHolder&) = delete;
~WindowHolder() override {
if (window_) {
window_->RemoveObserver(this);
}
}
aura::Window* window() { return window_.get(); }
bool is_valid() const { return !!window_; }
void OnWindowDestroying(aura::Window* window) override {
DCHECK_EQ(window, window_.get());
window_->RemoveObserver(this);
window_.release();
}
private:
std::unique_ptr<aura::Window> window_;
};
class DesksCloseAllTest : public DesksTest {
public:
DesksCloseAllTest()
: test_close_all_window_close_timeout_(
DesksTestApi::SetCloseAllWindowCloseTimeout(
base::Milliseconds(close_all_window_close_timeout_ms_))) {}
DesksCloseAllTest(const DesksCloseAllTest&) = delete;
DesksCloseAllTest& operator=(const DesksCloseAllTest&) = delete;
~DesksCloseAllTest() override = default;
void ClickOnCloseAllButtonForDesk(size_t index) {
ASSERT_TRUE(OverviewController::Get()->InOverviewSession());
const auto* desks_bar_view = GetPrimaryRootDesksBarView();
ASSERT_LT(index, desks_bar_view->mini_views().size());
LeftClickOn(desks_bar_view->mini_views()[index]
->desk_action_view()
->close_all_button());
RunScheduledLayoutForAllOverviewDeskBars();
}
void ExecuteContextMenuCloseAllForDesk(size_t index) {
ASSERT_TRUE(OverviewController::Get()->InOverviewSession());
const auto* desks_bar_view = GetPrimaryRootDesksBarView();
ASSERT_LT(index, desks_bar_view->mini_views().size());
auto* menu_controller = DesksTestApi::GetContextMenuForDesk(
DeskBarViewBase::Type::kOverview, index);
menu_controller->ExecuteCommand(
static_cast<int>(DeskActionContextMenu::CommandId::kCloseAll),
0);
}
void OpenContextMenuForMiniView(int index) {
ASSERT_TRUE(OverviewController::Get()->InOverviewSession());
const DeskPreviewView* desk_preview_view =
GetPrimaryRootDesksBarView()->mini_views()[index]->desk_preview();
const gfx::Point desk_preview_view_center =
desk_preview_view->GetBoundsInScreen().CenterPoint();
auto* event_generator = GetEventGenerator();
event_generator->MoveMouseTo(desk_preview_view_center);
event_generator->ClickRightButton();
ASSERT_TRUE(OverviewController::Get()->InOverviewSession());
}
void ClickOnUndoDeskRemovalButton() {
views::LabelButton* dismiss_button =
DesksTestApi::GetCloseAllUndoToastDismissButton();
const gfx::Point button_center =
dismiss_button->GetBoundsInScreen().CenterPoint();
auto* event_generator = GetEventGenerator();
event_generator->MoveMouseTo(button_center);
event_generator->ClickLeftButton();
}
protected:
const int close_all_window_close_timeout_ms_ = 20;
base::AutoReset<base::TimeDelta> test_close_all_window_close_timeout_;
};
TEST_P(DesksCloseAllTest, CloseDesksWithWindowsInOverview) {
enum class CloseAllSource {
kCloseAllButton,
kContextMenu,
};
struct {
const std::string scope_trace;
const CloseAllSource source;
} kTestCases[] = {
{"Remove desks using close all button", CloseAllSource::kCloseAllButton},
{"Remove desks using close all context menu option",
CloseAllSource::kContextMenu},
};
auto* controller = DesksController::Get();
for (const auto& test_case : kTestCases) {
SCOPED_TRACE(test_case.scope_trace);
NewDesk();
NewDesk();
ASSERT_EQ(3u, controller->desks().size());
Desk* desk_1 = controller->GetDeskAtIndex(0);
Desk* desk_2 = controller->GetDeskAtIndex(1);
Desk* desk_3 = controller->GetDeskAtIndex(2);
ASSERT_TRUE(desk_1->is_active());
WindowHolder win1(CreateAppWindow());
WindowHolder win2(CreateAppWindow());
controller->SendToDeskAtIndex(win1.window(), 0);
controller->SendToDeskAtIndex(win2.window(), 1);
ASSERT_EQ(1u, desk_1->windows().size());
ASSERT_EQ(1u, desk_2->windows().size());
EnterOverview();
ASSERT_TRUE(OverviewController::Get()->InOverviewSession());
if (test_case.source == CloseAllSource::kCloseAllButton) {
ClickOnCloseAllButtonForDesk(1);
SimulateWaitForCloseAll();
EXPECT_FALSE(DesksTestApi::DesksControllerHasDesk(desk_2));
EXPECT_TRUE(win1.is_valid());
EXPECT_FALSE(win2.is_valid());
ClickOnCloseAllButtonForDesk(0);
SimulateWaitForCloseAll();
EXPECT_FALSE(DesksTestApi::DesksControllerHasDesk(desk_1));
EXPECT_FALSE(win1.is_valid());
} else if (test_case.source == CloseAllSource::kContextMenu) {
ExecuteContextMenuCloseAllForDesk(1);
SimulateWaitForCloseAll();
EXPECT_FALSE(DesksTestApi::DesksControllerHasDesk(desk_2));
EXPECT_TRUE(win1.is_valid());
EXPECT_FALSE(win2.is_valid());
ExecuteContextMenuCloseAllForDesk(0);
SimulateWaitForCloseAll();
EXPECT_FALSE(DesksTestApi::DesksControllerHasDesk(desk_1));
EXPECT_FALSE(win1.is_valid());
}
EXPECT_TRUE(desk_3->is_active());
EXPECT_TRUE(OverviewController::Get()->InOverviewSession());
EXPECT_EQ(1u, GetPrimaryRootDesksBarView()->mini_views().size());
}
}
TEST_P(DesksCloseAllTest, ClearStoredDeskWhenDeskAdded) {
WindowHolder win1(CreateAppWindow());
WindowHolder win2(CreateAppWindow());
NewDesk();
auto* controller = DesksController::Get();
controller->SendToDeskAtIndex(win1.window(), 0);
controller->SendToDeskAtIndex(win2.window(), 1);
Desk* desk_1 = controller->GetDeskAtIndex(0);
Desk* desk_2 = controller->GetDeskAtIndex(1);
ASSERT_EQ(1u, desk_1->windows().size());
ASSERT_EQ(1u, desk_2->windows().size());
ASSERT_TRUE(desk_1->is_active());
EnterOverview();
ASSERT_TRUE(OverviewController::Get()->InOverviewSession());
RemoveDesk(desk_2, DeskCloseType::kCloseAllWindowsAndWait);
ASSERT_TRUE(desk_2->is_desk_being_removed());
ASSERT_EQ(1u, controller->desks().size());
ASSERT_TRUE(DesksTestApi::DesksControllerCanUndoDeskRemoval());
NewDesk();
EXPECT_EQ(2u, controller->desks().size());
EXPECT_FALSE(DesksTestApi::DesksControllerCanUndoDeskRemoval());
}
TEST_P(DesksCloseAllTest, ClearStoredDeskWhenClosingAnotherDesk) {
struct {
const std::string scope_trace;
const DeskCloseType desk_close_type;
} kTestCases[] = {
{"Remove second desk with close-all-and-wait",
DeskCloseType::kCloseAllWindowsAndWait},
{"Remove second desk with combine desks", DeskCloseType::kCombineDesks},
{"Remove second desk with close-all", DeskCloseType::kCloseAllWindows},
};
for (const auto& test_case : kTestCases) {
base::HistogramTester histogram_tester;
SCOPED_TRACE(test_case.scope_trace);
WindowHolder win1(CreateAppWindow());
WindowHolder win2(CreateAppWindow());
NewDesk();
NewDesk();
auto* controller = DesksController::Get();
controller->SendToDeskAtIndex(win1.window(), 0);
controller->SendToDeskAtIndex(win2.window(), 1);
Desk* desk_1 = controller->GetDeskAtIndex(0);
Desk* desk_2 = controller->GetDeskAtIndex(1);
Desk* desk_3 = controller->GetDeskAtIndex(2);
ASSERT_EQ(1u, desk_1->windows().size());
ASSERT_EQ(1u, desk_2->windows().size());
ASSERT_EQ(0u, desk_3->windows().size());
ASSERT_TRUE(desk_1->is_active());
EnterOverview();
ASSERT_TRUE(OverviewController::Get()->InOverviewSession());
RemoveDesk(desk_1, DeskCloseType::kCloseAllWindowsAndWait);
ASSERT_TRUE(desk_1->is_desk_being_removed());
ASSERT_EQ(2u, controller->desks().size());
ASSERT_TRUE(desk_2->is_active());
ASSERT_TRUE(DesksTestApi::DesksControllerCanUndoDeskRemoval());
EXPECT_EQ(GetPrimaryUserPrefService()->GetInteger(prefs::kDesksActiveDesk),
0);
RemoveDesk(desk_2, test_case.desk_close_type);
EXPECT_EQ(1u, controller->desks().size());
EXPECT_NE(desk_1, controller->GetDeskAtIndex(0));
EXPECT_NE(desk_2, controller->GetDeskAtIndex(0));
switch (test_case.desk_close_type) {
case DeskCloseType::kCloseAllWindowsAndWait:
EXPECT_TRUE(desk_2->is_desk_being_removed());
EXPECT_TRUE(DesksTestApi::DesksControllerCanUndoDeskRemoval());
break;
case DeskCloseType::kCombineDesks:
case DeskCloseType::kCloseAllWindows:
EXPECT_FALSE(DesksTestApi::DesksControllerCanUndoDeskRemoval());
break;
}
}
}
TEST_P(DesksCloseAllTest, RestoreOrDestroyDeskWithToast) {
struct {
const std::string scope_trace;
const bool restore_desk;
} kTestCases[] = {
{"Restore removed desk by undo", true},
{"Allow undo toast to expire", false},
};
WindowHolder window(CreateAppWindow());
NewDesk();
auto* controller = DesksController::Get();
ASSERT_EQ(2u, controller->desks().size());
controller->SendToDeskAtIndex(window.window(), 0);
Desk* desk_1 = controller->GetDeskAtIndex(0);
Desk* desk_2 = controller->GetDeskAtIndex(1);
ASSERT_EQ(1u, desk_1->windows().size());
ASSERT_EQ(0u, desk_2->windows().size());
ASSERT_TRUE(desk_1->is_active());
EnterOverview();
ASSERT_TRUE(OverviewController::Get()->InOverviewSession());
for (const auto& test_case : kTestCases) {
SCOPED_TRACE(test_case.scope_trace);
RemoveDesk(desk_1, DeskCloseType::kCloseAllWindowsAndWait);
ASSERT_TRUE(desk_1->is_desk_being_removed());
ASSERT_EQ(1u, controller->desks().size());
ASSERT_TRUE(desk_2->is_active());
ASSERT_TRUE(DesksTestApi::DesksControllerCanUndoDeskRemoval());
ASSERT_TRUE(window.is_valid());
EXPECT_EQ(GetPrimaryUserPrefService()->GetInteger(prefs::kDesksActiveDesk),
0);
if (test_case.restore_desk) {
ClickOnUndoDeskRemovalButton();
EXPECT_FALSE(desk_1->is_desk_being_removed());
EXPECT_EQ(2u, controller->desks().size());
EXPECT_TRUE(desk_1->is_active());
EXPECT_EQ(desk_1, controller->GetDeskAtIndex(0));
EXPECT_FALSE(DesksTestApi::DesksControllerCanUndoDeskRemoval());
EXPECT_TRUE(window.is_valid());
EXPECT_EQ(
GetPrimaryUserPrefService()->GetInteger(prefs::kDesksActiveDesk), 0);
} else {
GetEventGenerator()->MoveMouseTo(gfx::Point(0, 0));
SimulateWaitForCloseAll();
EXPECT_EQ(1u, controller->desks().size());
EXPECT_FALSE(DesksTestApi::DesksControllerCanUndoDeskRemoval());
EXPECT_FALSE(window.is_valid());
}
}
}
TEST_P(DesksCloseAllTest, HideCombineDesksOptionWhenNoWindowsOnDesk) {
NewDesk();
EnterOverview();
ASSERT_TRUE(OverviewController::Get()->InOverviewSession());
auto* event_generator = GetEventGenerator();
OpenContextMenuForMiniView(0);
EXPECT_EQ(1u, DesksTestApi::GetContextMenuModelForDesk(
DeskBarViewBase::Type::kOverview, 0)
.GetItemCount());
event_generator->ClickLeftButton();
auto window = CreateAppWindow();
DesksController::Get()->SendToDeskAtIndex(window.get(), 0);
EnterOverview();
ASSERT_TRUE(OverviewController::Get()->InOverviewSession());
OpenContextMenuForMiniView(0);
EXPECT_EQ(3u, DesksTestApi::GetContextMenuModelForDesk(
DeskBarViewBase::Type::kOverview, 0)
.GetItemCount());
}
TEST_P(DesksCloseAllTest, AccessibleName) {
NewDesk();
EnterOverview();
ASSERT_TRUE(OverviewController::Get()->InOverviewSession());
DeskMiniView* mini_view = GetPrimaryRootDesksBarView()->mini_views()[0];
ui::AXNodeData data;
mini_view->GetViewAccessibility().GetAccessibleNodeData(&data);
EXPECT_EQ(data.role,
mini_view->desk_preview()->GetViewAccessibility().GetCachedRole());
EXPECT_EQ(data.GetString16Attribute(ax::mojom::StringAttribute::kName),
l10n_util::GetStringFUTF16(IDS_ASH_DESKS_DESK_ACCESSIBLE_NAME,
mini_view->desk()->name()));
mini_view->desk()->SetName(u"Sample Desk Name", true);
data = ui::AXNodeData();
mini_view->GetViewAccessibility().GetAccessibleNodeData(&data);
EXPECT_EQ(data.GetString16Attribute(ax::mojom::StringAttribute::kName),
l10n_util::GetStringFUTF16(IDS_ASH_DESKS_DESK_ACCESSIBLE_NAME,
mini_view->desk()->name()));
}
TEST_P(DesksCloseAllTest, ShortcutCloseAll) {
WindowHolder window1(CreateAppWindow());
WindowHolder window2(CreateAppWindow());
NewDesk();
auto* controller = DesksController::Get();
ASSERT_EQ(2u, controller->desks().size());
Desk* desk_1 = controller->GetDeskAtIndex(0);
ASSERT_TRUE(desk_1->is_active());
ASSERT_TRUE(base::Contains(desk_1->windows(), window1.window()));
ASSERT_TRUE(base::Contains(desk_1->windows(), window2.window()));
EnterOverview();
auto* overview_session = OverviewController::Get()->overview_session();
ASSERT_TRUE(overview_session);
auto* desks_bar =
GetOverviewGridForRoot(Shell::GetPrimaryRootWindow())->desks_bar_view();
auto* mini_view = desks_bar->mini_views()[0].get();
PressAndReleaseKey(ui::VKEY_TAB);
PressAndReleaseKey(ui::VKEY_TAB);
PressAndReleaseKey(ui::VKEY_TAB);
ASSERT_TRUE(mini_view->desk_preview()->HasFocus());
PressAndReleaseKey(ui::VKEY_W, ui::EF_CONTROL_DOWN | ui::EF_SHIFT_DOWN);
SimulateWaitForCloseAll();
EXPECT_EQ(1u, controller->desks().size());
EXPECT_FALSE(window1.is_valid());
EXPECT_FALSE(window2.is_valid());
}
TEST_P(DesksCloseAllTest, ShortcutUndoCloseAll) {
WindowHolder window1(CreateAppWindow());
WindowHolder window2(CreateAppWindow());
NewDesk();
auto* controller = DesksController::Get();
ASSERT_EQ(2u, controller->desks().size());
Desk* desk_1 = controller->GetDeskAtIndex(0);
ASSERT_TRUE(desk_1->is_active());
ASSERT_TRUE(base::Contains(desk_1->windows(), window1.window()));
ASSERT_TRUE(base::Contains(desk_1->windows(), window2.window()));
EnterOverview();
auto* overview_session = OverviewController::Get()->overview_session();
ASSERT_TRUE(overview_session);
ClickOnCloseAllButtonForDesk(0);
ASSERT_TRUE(DesksTestApi::DesksControllerCanUndoDeskRemoval());
ASSERT_EQ(1u, controller->desks().size());
PressAndReleaseKey(ui::VKEY_Z, ui::EF_CONTROL_DOWN);
EXPECT_EQ(2u, controller->desks().size());
EXPECT_TRUE(window1.is_valid());
EXPECT_TRUE(window2.is_valid());
}
TEST_P(DesksCloseAllTest, CloseActiveDeskCloseWindows) {
WindowHolder window1(CreateAppWindow());
WindowHolder window2(CreateAppWindow());
NewDesk();
auto* controller = DesksController::Get();
ASSERT_EQ(2u, controller->desks().size());
Desk* desk_1 = controller->GetDeskAtIndex(0);
ASSERT_TRUE(desk_1->is_active());
ASSERT_TRUE(base::Contains(desk_1->windows(), window1.window()));
ASSERT_TRUE(base::Contains(desk_1->windows(), window2.window()));
RemoveDesk(desk_1, DeskCloseType::kCloseAllWindowsAndWait);
SimulateWaitForCloseAll();
EXPECT_EQ(1u, controller->desks().size());
EXPECT_FALSE(window1.is_valid());
EXPECT_FALSE(window2.is_valid());
}
TEST_P(DesksCloseAllTest, ForceCloseWindows) {
WindowHolder window1(CreateAppWindow());
WindowHolder window2(CreateAppWindow(
gfx::Rect(), chromeos::AppType::SYSTEM_APP,
ShellWindowId::kShellWindowId_Invalid, new StuckWidgetDelegate()));
NewDesk();
auto* controller = DesksController::Get();
ASSERT_EQ(2u, controller->desks().size());
Desk* desk_1 = controller->GetDeskAtIndex(0);
ASSERT_TRUE(desk_1->is_active());
ASSERT_TRUE(base::Contains(desk_1->windows(), window1.window()));
ASSERT_TRUE(base::Contains(desk_1->windows(), window2.window()));
RemoveDesk(desk_1, DeskCloseType::kCloseAllWindowsAndWait);
DesksController::Get()->MaybeCommitPendingDeskRemoval();
WaitForMilliseconds(close_all_window_close_timeout_ms_ / 2);
EXPECT_EQ(1u, controller->desks().size());
EXPECT_FALSE(window1.is_valid());
EXPECT_TRUE(window2.is_valid());
WaitForMilliseconds(close_all_window_close_timeout_ms_);
EXPECT_FALSE(window2.is_valid());
}
TEST_P(DesksCloseAllTest, DeskPreviewHighlightShowsWhenContextMenuIsOpen) {
UpdateDisplay("1366x768");
NewDesk();
EnterOverview();
ASSERT_TRUE(OverviewController::Get()->InOverviewSession());
views::View* highlight_overlay =
DesksTestApi::GetHighlightOverlayForDeskPreview(
DeskBarViewBase::Type::kOverview, 0);
ASSERT_FALSE(highlight_overlay->GetVisible());
DeskPreviewView* desk_preview_view =
GetPrimaryRootDesksBarView()->mini_views()[0]->desk_preview();
gfx::Point desk_preview_view_center =
desk_preview_view->GetBoundsInScreen().CenterPoint();
auto* event_generator = GetEventGenerator();
event_generator->MoveMouseTo(desk_preview_view_center);
event_generator->ClickRightButton();
ASSERT_TRUE(OverviewController::Get()->InOverviewSession());
ASSERT_TRUE(highlight_overlay->GetVisible());
event_generator->ClickLeftButton();
base::RunLoop().RunUntilIdle();
EXPECT_FALSE(highlight_overlay->GetVisible());
}
TEST_P(DesksCloseAllTest, TestMetricsRecordingWhenCloseAllWindows) {
struct {
const std::string scope_trace;
const bool restore_desk;
} kTestCases[] = {
{"Restore removed desk by undo", true},
{"Allow undo toast to expire", false},
};
base::HistogramTester histogram_tester;
WindowHolder window(CreateAppWindow());
WindowHolder window1(CreateAppWindow());
NewDesk();
auto* controller = DesksController::Get();
controller->SendToDeskAtIndex(window.window(), 0);
controller->SendToDeskAtIndex(window1.window(), 0);
EnterOverview();
int remove_desk_type_count = 0;
int undo_toast_expired_count = 0;
for (const auto& test_case : kTestCases) {
SCOPED_TRACE(test_case.scope_trace);
auto* menu_controller = DesksTestApi::GetContextMenuForDesk(
DeskBarViewBase::Type::kOverview, 0);
menu_controller->ExecuteCommand(
static_cast<int>(DeskActionContextMenu::CommandId::kCloseAll),
0);
RunScheduledLayoutForAllOverviewDeskBars();
histogram_tester.ExpectBucketCount("Ash.Desks.RemoveDeskType",
DeskCloseType::kCloseAllWindowsAndWait,
++remove_desk_type_count);
if (test_case.restore_desk) {
views::LabelButton* dismiss_button =
DesksTestApi::GetCloseAllUndoToastDismissButton();
const gfx::Point button_center =
dismiss_button->GetBoundsInScreen().CenterPoint();
auto* event_generator = GetEventGenerator();
event_generator->MoveMouseTo(button_center);
event_generator->ClickLeftButton();
RunScheduledLayoutForAllOverviewDeskBars();
histogram_tester.ExpectTotalCount("Ash.Desks.CloseAllUndo", 1);
histogram_tester.ExpectTotalCount("Ash.Desks.CloseAllTotal",
++undo_toast_expired_count);
histogram_tester.ExpectTotalCount("Ash.Desks.NumberOfWindowsClosed2", 0);
histogram_tester.ExpectTotalCount(
"Ash.Desks.NumberOfWindowsClosed2.Button", 0);
} else {
GetEventGenerator()->MoveMouseTo(gfx::Point(0, 0));
RunScheduledLayoutForAllOverviewDeskBars();
DesksController::Get()->MaybeCommitPendingDeskRemoval();
histogram_tester.ExpectTotalCount("Ash.Desks.CloseAllTotal",
++undo_toast_expired_count);
histogram_tester.ExpectUniqueSample("Ash.Desks.NumberOfWindowsClosed2", 2,
1);
histogram_tester.ExpectUniqueSample(
"Ash.Desks.NumberOfWindowsClosed2.Button", 2, 1);
}
}
}
TEST_P(DesksCloseAllTest, DeskPreviewAccessibleProperties) {
NewDesk();
EnterOverview();
ASSERT_TRUE(OverviewController::Get()->InOverviewSession());
DeskPreviewView* desk_preview_view =
GetPrimaryRootDesksBarView()->mini_views()[0]->desk_preview();
ui::AXNodeData data;
desk_preview_view->GetViewAccessibility().GetAccessibleNodeData(&data);
EXPECT_EQ(
data.GetString16Attribute(ax::mojom::StringAttribute::kRoleDescription),
l10n_util::GetStringUTF16(IDS_ASH_DESKS_DESK_PREVIEW_ROLE_DESCRIPTION));
}
TEST_P(DesksCloseAllTest, ContextMenuOpensOnLongPress) {
NewDesk();
EnterOverview();
ASSERT_TRUE(OverviewController::Get()->InOverviewSession());
const DeskPreviewView* desk_preview_view =
GetPrimaryRootDesksBarView()->mini_views()[0]->desk_preview();
const gfx::Point desk_preview_view_center =
desk_preview_view->GetBoundsInScreen().CenterPoint();
auto* event_generator = GetEventGenerator();
LongGestureTap(desk_preview_view_center, event_generator);
EXPECT_TRUE(DesksTestApi::IsContextMenuRunningForDesk(
DeskBarViewBase::Type::kOverview, 0));
}
TEST_P(DesksCloseAllTest, CanCloseMultipleDesksInSuccessionAndUndo) {
NewDesk();
NewDesk();
auto* controller = DesksController::Get();
ASSERT_EQ(3u, controller->desks().size());
EnterOverview();
ASSERT_TRUE(OverviewController::Get()->InOverviewSession());
ClickOnCloseAllButtonForDesk(0);
ASSERT_TRUE(DesksTestApi::DesksControllerCanUndoDeskRemoval());
ClickOnCloseAllButtonForDesk(0);
ASSERT_TRUE(DesksTestApi::DesksControllerCanUndoDeskRemoval());
ClickOnUndoDeskRemovalButton();
EXPECT_EQ(2u, controller->desks().size());
}
TEST_P(DesksCloseAllTest,
ActiveDeskWindowsAreRestoredProperlyOutsideOfOverview) {
WindowHolder window(CreateAppWindow());
NewDesk();
auto* controller = DesksController::Get();
ASSERT_EQ(2u, controller->desks().size());
controller->SendToDeskAtIndex(window.window(), 0);
Desk* desk_1 = controller->GetDeskAtIndex(0);
Desk* desk_2 = controller->GetDeskAtIndex(1);
ASSERT_EQ(1u, desk_1->windows().size());
ASSERT_EQ(0u, desk_2->windows().size());
ASSERT_TRUE(desk_1->is_active());
EnterOverview();
ASSERT_TRUE(OverviewController::Get()->InOverviewSession());
EXPECT_FALSE(window.window()->transform().IsIdentity());
ClickOnCloseAllButtonForDesk(0);
ExitOverview();
ASSERT_FALSE(OverviewController::Get()->InOverviewSession());
base::RunLoop().RunUntilIdle();
DeskSwitchAnimationWaiter waiter;
ClickOnUndoDeskRemovalButton();
waiter.Wait();
EXPECT_TRUE(window.is_valid());
EXPECT_TRUE(window.window()->transform().IsIdentity());
}
TEST_P(DesksCloseAllTest, CanAddLastDeskWhileUndoToastIsBeingDisplayed) {
auto* controller = DesksController::Get();
while (controller->desks().size() < desks_util::GetMaxNumberOfDesks()) {
NewDesk();
}
ASSERT_EQ(desks_util::GetMaxNumberOfDesks(), controller->desks().size());
WindowHolder window(CreateAppWindow());
const int last_desk_index = desks_util::GetMaxNumberOfDesks() - 1;
controller->SendToDeskAtIndex(window.window(), last_desk_index);
EnterOverview();
ASSERT_TRUE(OverviewController::Get()->InOverviewSession());
RemoveDesk(controller->GetDeskAtIndex(last_desk_index),
DeskCloseType::kCloseAllWindowsAndWait);
ASSERT_EQ(desks_util::GetMaxNumberOfDesks() - 1, controller->desks().size());
ASSERT_TRUE(DesksTestApi::DesksControllerCanUndoDeskRemoval());
auto* new_desk_button = GetPrimaryRootDesksBarView()->new_desk_button();
ASSERT_TRUE(new_desk_button->GetEnabled());
for (int i = 0; i != 3; ++i) {
TryScrollOverviewDeskBar(DeskBarScrollDirection::kRight);
}
LeftClickOn(new_desk_button);
EXPECT_EQ(desks_util::GetMaxNumberOfDesks(), controller->desks().size());
EXPECT_FALSE(DesksTestApi::DesksControllerCanUndoDeskRemoval());
WaitForMilliseconds(close_all_window_close_timeout_ms_);
EXPECT_FALSE(window.is_valid());
}
TEST_P(DesksCloseAllTest, ClosingWindowsHaveParent) {
WindowHolder window(CreateAppWindow(
gfx::Rect(), chromeos::AppType::SYSTEM_APP,
ShellWindowId::kShellWindowId_Invalid, new StuckWidgetDelegate()));
NewDesk();
auto* controller = DesksController::Get();
ASSERT_EQ(2u, controller->desks().size());
Desk* desk_1 = controller->GetDeskAtIndex(0);
ASSERT_TRUE(desk_1->is_active());
EXPECT_TRUE(base::Contains(desk_1->windows(), window.window()));
RemoveDesk(desk_1, DeskCloseType::kCloseAllWindowsAndWait);
DesksController::Get()->MaybeCommitPendingDeskRemoval();
WaitForMilliseconds(close_all_window_close_timeout_ms_ / 2);
ASSERT_EQ(1u, controller->desks().size());
ASSERT_TRUE(window.is_valid());
EXPECT_TRUE(window.window()->GetRootWindow());
EXPECT_EQ(kShellWindowId_UnparentedContainer,
window.window()->parent()->GetId());
}
TEST_P(DesksCloseAllTest, TestRecordingNumerOfClosedWindowsMetrics) {
struct {
const std::string scope_trace;
const DeskCloseType desk_close_type;
} kTestCases[] = {
{"Remove second desk with combine desks", DeskCloseType::kCombineDesks},
{"Remove second desk with close-all-and-wait",
DeskCloseType::kCloseAllWindowsAndWait},
{"Remove second desk with close-all", DeskCloseType::kCloseAllWindows},
};
for (const auto& test_case : kTestCases) {
base::HistogramTester histogram_tester;
SCOPED_TRACE(test_case.scope_trace);
WindowHolder win1(CreateAppWindow());
NewDesk();
auto* controller = DesksController::Get();
controller->SendToDeskAtIndex(win1.window(), 1);
Desk* desk = controller->GetDeskAtIndex(1);
EnterOverview();
RemoveDesk(desk, test_case.desk_close_type);
switch (test_case.desk_close_type) {
case DeskCloseType::kCombineDesks:
histogram_tester.ExpectTotalCount("Ash.Desks.NumberOfWindowsClosed2",
0);
histogram_tester.ExpectTotalCount(
"Ash.Desks.NumberOfWindowsClosed2.Button", 0);
break;
case DeskCloseType::kCloseAllWindowsAndWait:
GetEventGenerator()->MoveMouseTo(gfx::Point(0, 0));
DesksController::Get()->MaybeCommitPendingDeskRemoval();
WaitForMilliseconds(200);
histogram_tester.ExpectTotalCount("Ash.Desks.NumberOfWindowsClosed2",
1);
histogram_tester.ExpectUniqueSample(
"Ash.Desks.NumberOfWindowsClosed2.Button", 1, 1);
break;
case DeskCloseType::kCloseAllWindows:
histogram_tester.ExpectTotalCount("Ash.Desks.NumberOfWindowsClosed2",
1);
histogram_tester.ExpectUniqueSample(
"Ash.Desks.NumberOfWindowsClosed2.Button", 1, 1);
break;
}
}
}
TEST_P(DesksTest, DeskGuidsSaved) {
NewDesk();
auto* controller = DesksController::Get();
base::Uuid desk1_guid = controller->GetDeskAtIndex(0)->uuid();
base::Uuid desk2_guid = controller->GetDeskAtIndex(1)->uuid();
EXPECT_THAT(GetDeskRestoreGuids(GetPrimaryUserPrefService()),
testing::ElementsAre(desk1_guid, desk2_guid));
NewDesk();
base::Uuid desk3_guid = controller->GetDeskAtIndex(2)->uuid();
EnterOverview();
CloseDeskFromMiniView(GetOverviewGridForRoot(Shell::GetPrimaryRootWindow())
->desks_bar_view()
->mini_views()[1],
GetEventGenerator());
EXPECT_THAT(GetDeskRestoreGuids(GetPrimaryUserPrefService()),
testing::ElementsAre(desk1_guid, desk3_guid));
}
TEST_P(DesksTest, DeskGuidsReorder) {
NewDesk();
NewDesk();
auto* controller = DesksController::Get();
base::Uuid desk1_guid = controller->GetDeskAtIndex(0)->uuid();
base::Uuid desk2_guid = controller->GetDeskAtIndex(1)->uuid();
base::Uuid desk3_guid = controller->GetDeskAtIndex(2)->uuid();
EXPECT_THAT(GetDeskRestoreGuids(GetPrimaryUserPrefService()),
testing::ElementsAre(desk1_guid, desk2_guid, desk3_guid));
EnterOverview();
const auto* desks_bar_view =
GetOverviewGridForRoot(Shell::GetPrimaryRootWindow())->desks_bar_view();
std::vector<raw_ptr<DeskMiniView, VectorExperimental>> mini_views =
desks_bar_view->mini_views();
auto* event_generator = GetEventGenerator();
StartDragDeskPreview(mini_views[1], event_generator);
gfx::Point desk_center_2 =
mini_views[2]->GetPreviewBoundsInScreen().CenterPoint();
event_generator->MoveMouseTo(desk_center_2);
event_generator->ReleaseLeftButton();
EXPECT_THAT(GetDeskRestoreGuids(GetPrimaryUserPrefService()),
testing::ElementsAre(desk1_guid, desk3_guid, desk2_guid));
}
TEST_P(DesksCloseAllTest, InteractingWithShelfClosesToast) {
auto* shelf_model = ShelfModel::Get();
NewDesk();
WindowHolder window(CreateAppWindow());
const ash::ShelfID shelf_id("cool_app");
window.window()->SetProperty(ash::kShelfIDKey, shelf_id.Serialize());
window.window()->SetProperty(ash::kAppIDKey, shelf_id.app_id);
window.window()->SetProperty<int>(ash::kShelfItemTypeKey,
ShelfItemType::TYPE_PINNED_APP);
ShelfItem item;
item.status = ShelfItemStatus::STATUS_RUNNING;
item.type = ShelfItemType::TYPE_PINNED_APP;
item.id = shelf_id;
shelf_model->Add(item, std::make_unique<TestShelfItemDelegate>(item.id));
EnterOverview();
ASSERT_TRUE(OverviewController::Get()->InOverviewSession());
ClickOnCloseAllButtonForDesk(0);
int item_index = shelf_model->ItemIndexByID(shelf_id);
auto* view_model = GetPrimaryShelf()->GetShelfViewForTesting()->view_model();
views::View* item_view = view_model->view_at(item_index);
gfx::Point item_view_center = item_view->GetBoundsInScreen().CenterPoint();
auto* event_generator = GetEventGenerator();
event_generator->MoveMouseTo(item_view_center);
event_generator->ClickRightButton();
EXPECT_FALSE(DesksTestApi::DesksControllerCanUndoDeskRemoval());
base::RunLoop().RunUntilIdle();
EXPECT_FALSE(window.is_valid());
}
TEST_P(DesksCloseAllTest, UndoToastWorksWithChromevox) {
NewDesk();
Shell::Get()->accessibility_controller()->spoken_feedback().SetEnabled(true);
EnterOverview();
ASSERT_TRUE(OverviewController::Get()->InOverviewSession());
ClickOnCloseAllButtonForDesk(0);
ASSERT_EQ(1, DesksController::Get()->GetNumberOfDesks());
views::LabelButton* button =
DesksTestApi::GetCloseAllUndoToastDismissButton();
ASSERT_TRUE(button);
LeftClickOn(button);
EXPECT_EQ(2, DesksController::Get()->GetNumberOfDesks());
EXPECT_TRUE(OverviewController::Get()->InOverviewSession());
}
class DeskBarTest : public AshTestBase,
public ::testing::WithParamInterface<
testing::tuple<bool, bool, DeskBarViewBase::Type>> {
public:
DeskBarTest()
: test_close_all_window_close_timeout_(
DesksTestApi::SetCloseAllWindowCloseTimeout(
base::Milliseconds(20))) {}
DeskBarTest(const DeskBarTest&) = delete;
DeskBarTest& operator=(const DeskBarTest&) = delete;
~DeskBarTest() override = default;
void SetUp() override {
std::tie(use_touch_gestures_, use_16_desks_, bar_type_) = GetParam();
scoped_feature_list_.InitWithFeatureStates(
{{features::kFeatureManagement16Desks, use_16_desks_}});
AshTestBase::SetUp();
ash_test_helper()->saved_desk_test_helper()->WaitForDeskModels();
SetShowDeskButtonInShelfPref(GetPrimaryUserPrefService(), true);
}
void TearDown() override {
AshTestBase::TearDown();
scoped_feature_list_.Reset();
}
desks_storage::DeskModel* desk_model() {
return ash_test_helper()->saved_desk_test_helper()->desk_model();
}
void DeleteAllSavedDesks() {
base::RunLoop loop;
desk_model()->DeleteAllEntries(base::BindLambdaForTesting(
[&](desks_storage::DeskModel::DeleteEntryStatus status) {
loop.Quit();
}));
loop.Run();
}
void ClickOrPressOnPoint(const gfx::Point& p) {
auto* event_generator = GetEventGenerator();
if (use_touch_gestures_) {
event_generator->PressTouch(p);
event_generator->ReleaseTouch();
} else {
event_generator->MoveMouseTo(p);
event_generator->ClickLeftButton();
}
}
void ClickOrPressOnView(const views::View* view) {
const gfx::Point view_center = view->GetBoundsInScreen().CenterPoint();
ClickOrPressOnPoint(view_center);
}
void OpenDeskBar(aura::Window* root = Shell::Get()->GetPrimaryRootWindow()) {
OpenDeskBar(root, bar_type_);
}
void OpenDeskBar(aura::Window* root, DeskBarViewBase::Type bar_type) {
switch (bar_type) {
case DeskBarViewBase::Type::kOverview:
EnterOverview();
break;
case DeskBarViewBase::Type::kDeskButton:
DesksController::Get()->desk_bar_controller()->OpenDeskBar(root);
break;
}
DeskBarViewBase* const desk_bar_view = GetDeskBarView(root, bar_type);
if (desk_bar_view) {
views::test::RunScheduledLayout(desk_bar_view);
}
}
void CloseDeskBar(aura::Window* root = Shell::Get()->GetPrimaryRootWindow()) {
CloseDeskBar(root, bar_type_);
}
void CloseDeskBar(aura::Window* root, DeskBarViewBase::Type bar_type) {
switch (bar_type) {
case DeskBarViewBase::Type::kOverview:
ExitOverview();
break;
case DeskBarViewBase::Type::kDeskButton:
DesksController::Get()->desk_bar_controller()->CloseDeskBar(root);
break;
}
}
DeskBarViewBase* GetDeskBarView(
aura::Window* root = Shell::Get()->GetPrimaryRootWindow()) {
return GetDeskBarView(root, bar_type_);
}
DeskBarViewBase* GetDeskBarView(aura::Window* root,
DeskBarViewBase::Type bar_type) {
DeskBarViewBase* desk_bar_view = nullptr;
switch (bar_type) {
case DeskBarViewBase::Type::kOverview:
if (OverviewController::Get()->InOverviewSession()) {
desk_bar_view = GetOverviewGridForRoot(root)->desks_bar_view();
}
break;
case DeskBarViewBase::Type::kDeskButton:
desk_bar_view =
DesksController::Get()->desk_bar_controller()->GetDeskBarView(root);
break;
}
return desk_bar_view;
}
void EnterLibrary(aura::Window* root = Shell::Get()->GetPrimaryRootWindow()) {
EnterLibrary(root, bar_type_);
}
void EnterLibrary(aura::Window* root, DeskBarViewBase::Type bar_type) {
auto* desk_bar_view = GetDeskBarView(root, bar_type);
ASSERT_TRUE(desk_bar_view);
ASSERT_TRUE(desk_bar_view->library_button());
ASSERT_TRUE(desk_bar_view->library_button()->GetVisible());
ClickOrPressOnView(desk_bar_view->library_button());
auto* overview_controller = OverviewController::Get();
ASSERT_TRUE(overview_controller->InOverviewSession());
RunScheduledLayoutForAllOverviewDeskBars();
auto* overview_session = overview_controller->overview_session();
EXPECT_TRUE(overview_session &&
overview_session->IsShowingSavedDeskLibrary());
EXPECT_FALSE(GetDeskBarView(root, DeskBarViewBase::Type::kDeskButton));
EXPECT_TRUE(GetDeskBarView(root, DeskBarViewBase::Type::kOverview));
}
void ExecuteContextMenuDeskActionForDesk(size_t index,
bool close_all,
aura::Window* root,
DeskBarViewBase::Type bar_type) {
const auto* desks_bar_view = GetDeskBarView(root, bar_type);
ASSERT_LT(index, desks_bar_view->mini_views().size());
auto* menu_controller =
DesksTestApi::GetContextMenuForDesk(bar_type, index);
const int command_id = static_cast<int>(
close_all ? DeskActionContextMenu::CommandId::kCloseAll
: DeskActionContextMenu::CommandId::kCombineDesks);
if (bar_type == DeskBarViewBase::Type::kDeskButton &&
desks_bar_view->mini_views()[index]->desk()->is_active()) {
DeskSwitchAnimationWaiter waiter;
menu_controller->ExecuteCommand(command_id,
0);
waiter.Wait();
} else {
menu_controller->ExecuteCommand(command_id,
0);
}
}
void CloseDeskWithButton(size_t index,
bool close_all,
aura::Window* root,
DeskBarViewBase::Type bar_type) {
if (use_touch_gestures_) {
ExecuteContextMenuDeskActionForDesk(index, close_all, root, bar_type);
} else {
const auto* desk_bar_view = GetDeskBarView(root, bar_type);
ASSERT_LT(index, desk_bar_view->mini_views().size());
auto* target_mini_view = desk_bar_view->mini_views()[index].get();
GetEventGenerator()->MoveMouseTo(
target_mini_view->desk_preview()->GetBoundsInScreen().CenterPoint());
auto* target_button =
close_all
? target_mini_view->desk_action_view()->close_all_button()
: target_mini_view->desk_action_view()->combine_desks_button();
ASSERT_TRUE(target_button->GetVisible());
if (bar_type == DeskBarViewBase::Type::kDeskButton &&
target_mini_view->desk()->is_active()) {
DeskSwitchAnimationWaiter waiter;
LeftClickOn(target_button);
waiter.Wait();
} else {
LeftClickOn(target_button);
}
}
}
void CombineDeskWithMenu(size_t index,
aura::Window* root,
DeskBarViewBase::Type bar_type) {
views::MenuItemView* menu_item =
DesksTestApi::OpenDeskContextMenuAndGetMenuItem(
root, bar_type, index,
DeskActionContextMenu::CommandId::kCombineDesks);
ASSERT_TRUE(menu_item);
if (bar_type == DeskBarViewBase::Type::kDeskButton &&
DesksController::Get()->GetActiveDeskIndex() ==
static_cast<int>(index)) {
DeskSwitchAnimationWaiter waiter;
LeftClickOn(menu_item);
waiter.Wait();
} else {
LeftClickOn(menu_item);
}
}
bool use_touch_gestures_;
bool use_16_desks_;
DeskBarViewBase::Type bar_type_;
private:
base::AutoReset<base::TimeDelta> test_close_all_window_close_timeout_;
base::test::ScopedFeatureList scoped_feature_list_;
};
TEST_P(DeskBarTest, DeskTextfieldOutsideOverview) {
auto widget =
views::test::TestWidgetBuilder()
.SetDelegate(nullptr)
.SetBounds(gfx::Rect(0, 0, 300, 300))
.SetParent(Shell::GetPrimaryRootWindow())
.SetShow(true)
.SetWidgetType(views::Widget::InitParams::TYPE_WINDOW_FRAMELESS)
.BuildOwnsNativeWidget();
auto* desk_text_view = widget->SetContentsView(
std::make_unique<DeskTextfield>(SystemTextfield::Type::kSmall));
desk_text_view->CommitChanges(widget.get());
}
TEST_P(DeskBarTest, ShutdownNoAnimation) {
OpenDeskBar();
}
TEST_P(DeskBarTest, ShutdownWithAnimation) {
gfx::ScopedAnimationDurationScaleMode animation_scale(
gfx::ScopedAnimationDurationScaleMode::NON_ZERO_DURATION);
OpenDeskBar();
}
struct DeskBarTestBasicCase {
std::string test_name;
std::vector<int> desks;
int active_desk;
ShelfAlignment shelf_alignment;
bool has_saved_desks;
gfx::Rect desk_button_bar_widget_bounds;
gfx::Rect desk_button_bar_view_bounds;
gfx::Rect overview_bar_widget_bounds;
gfx::Rect overview_bar_view_bounds;
};
TEST_P(DeskBarTest, Basic) {
UpdateDisplay("800x600");
const int expected_expanded_overview_height = 114;
const DeskBarTestBasicCase tests[] = {
{.test_name = "single desk + bottom shelf + saved desks",
.desks = {0},
.active_desk = 0,
.shelf_alignment = ShelfAlignment::kBottom,
.has_saved_desks = true,
.desk_button_bar_widget_bounds = {299, 446, 202, 98},
.desk_button_bar_view_bounds = {0, 0, 202, 98},
.overview_bar_widget_bounds = {0, 0, 800, 40},
.overview_bar_view_bounds = {0, 0, 800, 40}},
{.test_name = "single desk + bottom shelf",
.desks = {0},
.active_desk = 0,
.shelf_alignment = ShelfAlignment::kBottom,
.has_saved_desks = false,
.desk_button_bar_widget_bounds = {323, 446, 154, 98},
.desk_button_bar_view_bounds = {0, 0, 154, 98},
.overview_bar_widget_bounds = {0, 0, 800, 40},
.overview_bar_view_bounds = {0, 0, 800, 40}},
{.test_name = "single desk + left shelf + saved desks",
.desks = {0},
.active_desk = 0,
.shelf_alignment = ShelfAlignment::kLeft,
.has_saved_desks = true,
.desk_button_bar_widget_bounds = {56, 247, 202, 98},
.desk_button_bar_view_bounds = {0, 0, 202, 98},
.overview_bar_widget_bounds = {48, 0, 752, 40},
.overview_bar_view_bounds = {0, 0, 752, 40}},
{.test_name = "single desk + right shelf + saved desks",
.desks = {0},
.active_desk = 0,
.shelf_alignment = ShelfAlignment::kRight,
.has_saved_desks = true,
.desk_button_bar_widget_bounds = {542, 247, 202, 98},
.desk_button_bar_view_bounds = {0, 0, 202, 98},
.overview_bar_widget_bounds = {0, 0, 752, 40},
.overview_bar_view_bounds = {0, 0, 752, 40}},
{.test_name = "multiple desks + bottom shelf + saved desks",
.desks = {0, 1, 2},
.active_desk = 0,
.shelf_alignment = ShelfAlignment::kBottom,
.has_saved_desks = true,
.desk_button_bar_widget_bounds = {221, 446, 358, 98},
.desk_button_bar_view_bounds = {0, 0, 358, 98},
.overview_bar_widget_bounds = {0, 0, 800,
expected_expanded_overview_height},
.overview_bar_view_bounds = {0, 0, 800,
expected_expanded_overview_height}},
};
auto* desks_controller = DesksController::Get();
Shelf* shelf = GetPrimaryShelf();
for (const auto& test : tests) {
SCOPED_TRACE(test.test_name);
while (desks_controller->GetNumberOfDesks() < (int)test.desks.size()) {
NewDesk();
}
if (!desks_controller->GetDeskAtIndex(test.active_desk)->is_active()) {
ActivateDesk(desks_controller->GetDeskAtIndex(test.active_desk));
}
shelf->SetAlignment(test.shelf_alignment);
if (test.has_saved_desks) {
AddSavedDeskEntry(desk_model(), base::Uuid::GenerateRandomV4(),
"saved_desk_1", base::Time::Now(),
DeskTemplateType::kSaveAndRecall);
}
OpenDeskBar();
auto* desk_bar_view = GetDeskBarView();
ASSERT_TRUE(desk_bar_view);
ASSERT_TRUE(desk_bar_view->GetVisible());
auto* desk_bar_widget = desk_bar_view->GetWidget();
ASSERT_TRUE(desk_bar_widget);
if (bar_type_ == DeskBarViewBase::Type::kOverview) {
EXPECT_THAT(desk_bar_widget->GetWindowBoundsInScreen(),
test.overview_bar_widget_bounds);
EXPECT_THAT(desk_bar_view->bounds(), test.overview_bar_view_bounds);
EXPECT_THAT(desk_bar_view->IsZeroState(), test.desks.size() == 1);
} else {
EXPECT_THAT(desk_bar_widget->GetWindowBoundsInScreen(),
test.desk_button_bar_widget_bounds);
EXPECT_THAT(desk_bar_view->bounds(), test.desk_button_bar_view_bounds);
EXPECT_FALSE(desk_bar_view->IsZeroState());
}
auto* new_desk_button = desk_bar_view->new_desk_button();
const auto expected_button_state =
bar_type_ == DeskBarViewBase::Type::kOverview && test.desks.size() == 1
? DeskIconButton::State::kZero
: DeskIconButton::State::kExpanded;
EXPECT_THAT(new_desk_button->state(), expected_button_state);
EXPECT_TRUE(new_desk_button->GetVisible());
EXPECT_THAT(new_desk_button->GetEnabled(),
desks_controller->CanCreateDesks());
auto* library_button = desk_bar_view->library_button();
EXPECT_THAT(IsLazyInitViewVisible(library_button), test.has_saved_desks);
if (library_button) {
EXPECT_THAT(library_button->state(), expected_button_state);
EXPECT_TRUE(library_button->GetEnabled());
}
CloseDeskBar();
while (desks_controller->CanRemoveDesks()) {
RemoveDesk(desks_controller->desks().back().get());
}
DeleteAllSavedDesks();
}
}
TEST_P(DeskBarTest, BasicSecondaryDisplay) {
UpdateDisplay("800x600,800x600");
NewDesk();
aura::Window* root = Shell::Get()->GetAllRootWindows().back();
OpenDeskBar(root);
auto* desk_bar_view = GetDeskBarView(root);
ASSERT_TRUE(desk_bar_view);
ASSERT_TRUE(desk_bar_view->GetVisible());
auto* desk_bar_widget = desk_bar_view->GetWidget();
ASSERT_TRUE(desk_bar_widget);
const int expected_expanded_overview_height = 114;
if (bar_type_ == DeskBarViewBase::Type::kOverview) {
EXPECT_THAT(desk_bar_widget->GetWindowBoundsInScreen(),
gfx::Rect(800, 0, 800, expected_expanded_overview_height));
EXPECT_THAT(desk_bar_view->bounds(),
gfx::Rect(0, 0, 800, expected_expanded_overview_height));
EXPECT_FALSE(desk_bar_view->IsZeroState());
} else {
EXPECT_THAT(desk_bar_widget->GetWindowBoundsInScreen(),
gfx::Rect(1084, 446, 232, 98));
EXPECT_THAT(desk_bar_view->bounds(), gfx::Rect(0, 0, 232, 98));
EXPECT_FALSE(desk_bar_view->IsZeroState());
}
CloseDeskBar(root);
}
TEST_P(DeskBarTest, ScrollLayout) {
UpdateDisplay("600x400");
auto* desks_controller = DesksController::Get();
while (desks_controller->CanCreateDesks()) {
NewDesk();
}
OpenDeskBar();
auto* left_scroll_button =
DesksTestApi::GetDeskBarLeftScrollButton(bar_type_);
ASSERT_TRUE(left_scroll_button);
auto* right_scroll_button =
DesksTestApi::GetDeskBarRightScrollButton(bar_type_);
ASSERT_TRUE(right_scroll_button);
EXPECT_FALSE(left_scroll_button->GetVisible());
EXPECT_TRUE(right_scroll_button->GetVisible());
while (right_scroll_button->GetVisible()) {
ClickOrPressOnView(right_scroll_button);
EXPECT_TRUE(left_scroll_button->GetVisible());
}
while (left_scroll_button->GetVisible()) {
ClickOrPressOnView(left_scroll_button);
EXPECT_TRUE(right_scroll_button->GetVisible());
}
CloseDeskBar();
}
TEST_P(DeskBarTest, HoverBasic) {
auto window_1 = CreateAppWindow(gfx::Rect(0, 0, 100, 100));
auto window_2 = CreateAppWindow(gfx::Rect(0, 0, 100, 100));
NewDesk();
auto* desks_controller = DesksController::Get();
desks_controller->SendToDeskAtIndex(window_1.get(), 0);
desks_controller->SendToDeskAtIndex(window_2.get(), 1);
OpenDeskBar();
for (int i = 0; i < desks_controller->GetNumberOfDesks(); i++) {
auto* event_generator = GetEventGenerator();
auto* mini_view = GetDeskBarView()->mini_views()[i].get();
EXPECT_FALSE(DesksTestApi::IsDeskShortcutViewVisible(mini_view));
event_generator->MoveMouseTo(
mini_view->desk_preview()->GetBoundsInScreen().CenterPoint());
EXPECT_TRUE(mini_view->desk_action_view()->context_menu_button());
EXPECT_TRUE(
mini_view->desk_action_view()->context_menu_button()->GetVisible());
EXPECT_TRUE(
mini_view->desk_action_view()->close_all_button()->GetVisible());
const bool expected_visibility =
i <= 7 && bar_type_ == DeskBarViewBase::Type::kDeskButton;
EXPECT_EQ(DesksTestApi::IsDeskShortcutViewVisible(mini_view),
expected_visibility);
}
CloseDeskBar();
}
TEST_P(DeskBarTest, NewDeskButton) {
OpenDeskBar();
auto* desks_controller = DesksController::Get();
auto* desk_bar_view = GetDeskBarView();
auto* new_desk_button = desk_bar_view->new_desk_button();
auto verify_disabled_new_desk_button = [&]() {
EXPECT_THAT(desks_controller->GetNumberOfDesks(),
desks_util::GetMaxNumberOfDesks());
EXPECT_FALSE(desks_controller->CanCreateDesks());
EXPECT_FALSE(new_desk_button->GetEnabled());
EXPECT_THAT(new_desk_button->GetState(), views::Button::STATE_DISABLED);
EXPECT_THAT(desk_bar_view->mini_views().size(),
desks_controller->GetNumberOfDesks());
};
auto verify_enabled_new_desk_button = [&](bool zero_state_bar) {
EXPECT_LE(desks_controller->GetNumberOfDesks(),
(int)desks_util::GetMaxNumberOfDesks());
EXPECT_TRUE(desks_controller->CanCreateDesks());
EXPECT_THAT(desk_bar_view->IsZeroState(), zero_state_bar);
EXPECT_TRUE(new_desk_button->GetEnabled());
EXPECT_NE(new_desk_button->GetState(), views::Button::STATE_DISABLED);
EXPECT_THAT(desk_bar_view->mini_views().size(),
zero_state_bar ? 0 : desks_controller->GetNumberOfDesks());
};
for (int i = 2; i <= (int)desks_util::GetMaxNumberOfDesks(); i++) {
const bool zero_state_bar =
bar_type_ == DeskBarViewBase::Type::kOverview && i == 2;
verify_enabled_new_desk_button(zero_state_bar);
ClickOrPressOnView(new_desk_button);
EXPECT_TRUE(desks_controller->CanRemoveDesks());
EXPECT_THAT(desks_controller->GetNumberOfDesks(), i);
views::test::RunScheduledLayout(desk_bar_view);
}
verify_disabled_new_desk_button();
ClickOrPressOnView(new_desk_button);
verify_disabled_new_desk_button();
CloseDeskBar();
}
TEST_P(DeskBarTest, LibraryButton) {
gfx::ScopedAnimationDurationScaleMode animation_scale(
gfx::ScopedAnimationDurationScaleMode::NON_ZERO_DURATION);
AddSavedDeskEntry(desk_model(), base::Uuid::GenerateRandomV4(),
"saved_desk_1", base::Time::Now(),
DeskTemplateType::kSaveAndRecall);
auto test_library_button = [&](const std::string& trace_message) {
SCOPED_TRACE(trace_message);
OpenDeskBar();
if (bar_type_ == DeskBarViewBase::Type::kOverview) {
WaitForOverviewEnterAnimation();
}
EnterLibrary();
auto* root = Shell::GetPrimaryRootWindow();
if (bar_type_ == DeskBarViewBase::Type::kOverview) {
DesksTestApi::WaitForDeskBarUiUpdate(
GetDeskBarView(root, DeskBarViewBase::Type::kOverview));
}
const views::FocusRing* library_button_focus_ring =
views::FocusRing::Get(GetPrimaryRootDesksBarView()->library_button());
ASSERT_TRUE(library_button_focus_ring);
ASSERT_TRUE(library_button_focus_ring->GetVisible());
EXPECT_FALSE(library_button_focus_ring->GetVisibleBounds().IsEmpty());
CloseDeskBar(root, DeskBarViewBase::Type::kOverview);
};
test_library_button("no app window");
auto window = CreateAppWindow(gfx::Rect(0, 0, 100, 100));
test_library_button("one app window");
}
TEST_P(DeskBarTest, ReorderDesk) {
OpenDeskBar();
auto* desks_controller = DesksController::Get();
auto* desk_bar_view = GetDeskBarView();
auto* event_generator = GetEventGenerator();
std::vector<std::string> desk_names = {"1", "2", "3"};
for (auto i = 0; auto desk_name : desk_names) {
if (desks_controller->GetNumberOfDesks() - 1 < i) {
NewDesk();
}
desks_controller->GetDeskAtIndex(i)->SetName(base::UTF8ToUTF16(desk_name),
true);
EXPECT_THAT(desk_bar_view->mini_views().size(),
GetDeskBarView()->IsZeroState()
? 0
: desks_controller->GetNumberOfDesks());
i++;
}
views::test::RunScheduledLayout(desk_bar_view);
desks_restore_util::UpdatePrimaryUserDeskNamesPrefs();
auto verify_desks = [&]() {
for (int i = 0; i < desks_controller->GetNumberOfDesks(); i++) {
EXPECT_THAT(desks_controller->GetDeskAtIndex(i)->name(),
base::UTF8ToUTF16(desk_names[i]));
}
auto* prefs =
Shell::Get()->session_controller()->GetPrimaryUserPrefService();
EXPECT_THAT(GetDeskRestoreNames(prefs),
::testing::ElementsAreArray(desk_names));
};
auto drag_desk = [&](int from, int to) {
SCOPED_TRACE("Swap desk " + base::NumberToString(from) + " with desk " +
base::NumberToString(to));
StartDragDeskPreview(desk_bar_view->mini_views()[from], event_generator);
EXPECT_TRUE(desk_bar_view->IsDraggingDesk());
event_generator->MoveMouseTo(desk_bar_view->mini_views()[to]
->GetPreviewBoundsInScreen()
.CenterPoint());
event_generator->ReleaseLeftButton();
EXPECT_FALSE(desk_bar_view->IsDraggingDesk());
std::string dragged_desk = desk_names[from];
if (from <= to) {
for (int i = from + 1; i <= to; i++) {
desk_names[i - 1] = desk_names[i];
}
} else {
for (int i = from - 1; i >= to; i--) {
desk_names[i + 1] = desk_names[i];
}
}
desk_names[to] = dragged_desk;
verify_desks();
};
verify_desks();
drag_desk(0, 1);
drag_desk(1, 2);
drag_desk(0, 1);
drag_desk(2, 0);
CloseDeskBar();
}
TEST_P(DeskBarTest, KeyboardReorderDesk) {
OpenDeskBar();
auto* desks_controller = DesksController::Get();
auto* desk_bar_view = GetDeskBarView();
NewDesk();
NewDesk();
std::vector<base::Uuid> desk_uuids;
for (auto& desk : desks_controller->desks()) {
desk_uuids.push_back(desk->uuid());
}
auto verify_desk_uuids = [&]() {
for (int i = 0; i < desks_controller->GetNumberOfDesks(); i++) {
EXPECT_THAT(desks_controller->GetDeskAtIndex(i)->uuid(), desk_uuids[i]);
}
};
auto verify_shortcut_label = [&](auto* mini_view, int desk_index) {
const bool expected_shortcut_visibility =
bar_type_ == DeskBarViewBase::Type::kDeskButton;
ASSERT_EQ(DesksTestApi::IsDeskShortcutViewVisible(mini_view),
expected_shortcut_visibility);
if (expected_shortcut_visibility) {
views::Label* label = DesksTestApi::GetDeskShortcutLabel(mini_view);
ASSERT_TRUE(label);
EXPECT_EQ(base::NumberToString16(desk_index + 1), label->GetText());
}
};
auto swap_desk = [&](int desk_index, bool left) {
SCOPED_TRACE("Swap desk " + base::NumberToString(desk_index) + " to the " +
(left ? "left" : "right"));
ASSERT_FALSE(desk_index == 0 && left);
ASSERT_FALSE(desk_index == 2 && !left);
auto* mini_view = desk_bar_view->mini_views()[desk_index].get();
mini_view->desk_preview()->RequestFocus();
verify_shortcut_label(mini_view, desk_index);
PressAndReleaseKey(left ? ui::VKEY_LEFT : ui::VKEY_RIGHT,
ui::EF_CONTROL_DOWN);
const int new_index = desk_index + (left ? -1 : 1);
EXPECT_EQ(mini_view, desk_bar_view->mini_views()[new_index]);
verify_shortcut_label(mini_view, new_index);
std::swap(desk_uuids[desk_index], desk_uuids[new_index]);
verify_desk_uuids();
};
verify_desk_uuids();
swap_desk(0, false);
swap_desk(1, false);
swap_desk(0, false);
swap_desk(1, false);
swap_desk(1, true);
swap_desk(2, true);
swap_desk(1, true);
swap_desk(0, false);
swap_desk(2, true);
swap_desk(1, false);
swap_desk(1, true);
CloseDeskBar();
}
TEST_P(DeskBarTest, ActivateDesk) {
auto* desks_controller = DesksController::Get();
NewDesk();
EXPECT_THAT(desks_controller->GetActiveDeskIndex(), 0);
OpenDeskBar();
ClickOrPressOnView(GetDeskBarView()->mini_views()[0]);
EXPECT_THAT(desks_controller->GetActiveDeskIndex(), 0);
EXPECT_FALSE(GetDeskBarView());
OpenDeskBar();
DeskSwitchAnimationWaiter waiter;
ClickOrPressOnView(GetDeskBarView()->mini_views()[1]);
waiter.Wait();
EXPECT_THAT(desks_controller->GetActiveDeskIndex(), 1);
EXPECT_FALSE(GetDeskBarView());
}
TEST_P(DeskBarTest, CombineOrCloseDesk) {
NewDesk();
NewDesk();
auto window = CreateAppWindow(gfx::Rect(0, 0, 100, 100));
auto* desks_controller = DesksController::Get();
desks_controller->SendToDeskAtIndex(window.get(), 2);
OpenDeskBar();
for (int desk_index = desks_controller->GetNumberOfDesks() - 1;
desk_index > 0; desk_index--) {
CloseDeskFromMiniView(GetDeskBarView()->mini_views()[desk_index],
GetEventGenerator());
EXPECT_THAT(GetDeskBarView()->mini_views().size(),
GetDeskBarView()->IsZeroState() ? 0 : desk_index);
}
CloseDeskBar();
}
TEST_P(DeskBarTest, DeskRenameKeyEsc) {
NewDesk();
OpenDeskBar();
auto* desk_bar_view = GetDeskBarView();
Desk* desk = DesksController::Get()->GetDeskAtIndex(0);
auto* mini_view = desk_bar_view->FindMiniViewForDesk(desk);
auto* desk_name_view = mini_view->desk_name_view();
ClickOrPressOnView(desk_name_view);
ASSERT_TRUE(desk_name_view->HasFocus());
PressAndReleaseKey(ui::VKEY_D, ui::EF_SHIFT_DOWN);
PressAndReleaseKey(ui::VKEY_1);
PressAndReleaseKey(ui::VKEY_ESCAPE);
EXPECT_FALSE(desk_name_view->HasFocus());
EXPECT_FALSE(desk->is_name_set_by_user());
EXPECT_THAT(desk_name_view->GetText(), u"Desk 1");
CloseDeskBar();
}
TEST_P(DeskBarTest, DeskRenameKeyReturn) {
NewDesk();
OpenDeskBar();
auto* desk_bar_view = GetDeskBarView();
Desk* desk = DesksController::Get()->GetDeskAtIndex(0);
auto* mini_view = desk_bar_view->FindMiniViewForDesk(desk);
auto* desk_name_view = mini_view->desk_name_view();
ClickOrPressOnView(desk_name_view);
ASSERT_TRUE(desk_name_view->HasFocus());
PressAndReleaseKey(ui::VKEY_D, ui::EF_SHIFT_DOWN);
PressAndReleaseKey(ui::VKEY_1);
PressAndReleaseKey(ui::VKEY_RETURN);
EXPECT_FALSE(desk_name_view->HasFocus());
EXPECT_TRUE(desk->is_name_set_by_user());
EXPECT_THAT(desk_name_view->GetText(), u"D1");
CloseDeskBar();
}
TEST_P(DeskBarTest, DeskRenameKeyTab) {
NewDesk();
OpenDeskBar();
auto* desk_bar_view = GetDeskBarView();
Desk* desk = DesksController::Get()->desks().front().get();
auto* mini_view = desk_bar_view->FindMiniViewForDesk(desk);
auto* desk_name_view = mini_view->desk_name_view();
ClickOrPressOnView(desk_name_view);
ASSERT_TRUE(desk_name_view->HasFocus());
PressAndReleaseKey(ui::VKEY_D, ui::EF_SHIFT_DOWN);
PressAndReleaseKey(ui::VKEY_1);
PressAndReleaseKey(ui::VKEY_TAB);
EXPECT_FALSE(desk_name_view->HasFocus());
EXPECT_TRUE(desk->is_name_set_by_user());
EXPECT_THAT(desk_name_view->GetText(), u"D1");
ASSERT_TRUE(desk_bar_view->mini_views()[1]->desk_preview()->HasFocus());
CloseDeskBar();
}
TEST_P(DeskBarTest, DeskRenameKeyShiftTab) {
NewDesk();
OpenDeskBar();
auto* desk_bar_view = GetDeskBarView();
Desk* desk = DesksController::Get()->desks().front().get();
auto* mini_view = desk_bar_view->FindMiniViewForDesk(desk);
auto* desk_name_view = mini_view->desk_name_view();
ClickOrPressOnView(desk_name_view);
ASSERT_TRUE(desk_name_view->HasFocus());
PressAndReleaseKey(ui::VKEY_D, ui::EF_SHIFT_DOWN);
PressAndReleaseKey(ui::VKEY_1);
PressAndReleaseKey(ui::VKEY_TAB, ui::EF_SHIFT_DOWN);
EXPECT_FALSE(desk_name_view->HasFocus());
EXPECT_TRUE(desk->is_name_set_by_user());
EXPECT_THAT(desk_name_view->GetText(), u"D1");
ASSERT_TRUE(mini_view->desk_action_view()->close_all_button()->HasFocus());
CloseDeskBar();
}
TEST_P(DeskBarTest, DeskRenameClickOnBar) {
NewDesk();
OpenDeskBar();
auto* desk_bar_view = GetDeskBarView();
Desk* desk = DesksController::Get()->GetDeskAtIndex(0);
auto* mini_view = desk_bar_view->FindMiniViewForDesk(desk);
auto* desk_name_view = mini_view->desk_name_view();
ClickOrPressOnView(desk_name_view);
ASSERT_TRUE(desk_name_view->HasFocus());
PressAndReleaseKey(ui::VKEY_D, ui::EF_SHIFT_DOWN);
PressAndReleaseKey(ui::VKEY_1);
gfx::Point empty_point = desk_bar_view->GetBoundsInScreen().top_center();
empty_point.Offset(0, 2);
ClickOrPressOnPoint(empty_point);
EXPECT_FALSE(desk_name_view->HasFocus());
EXPECT_TRUE(desk->is_name_set_by_user());
EXPECT_THAT(desk_name_view->GetText(), u"D1");
CloseDeskBar();
}
TEST_P(DeskBarTest, DeskRenameClickOffBar) {
NewDesk();
OpenDeskBar();
auto* desk_bar_view = GetDeskBarView();
Desk* desk = DesksController::Get()->GetDeskAtIndex(0);
auto* mini_view = desk_bar_view->FindMiniViewForDesk(desk);
auto* desk_name_view = mini_view->desk_name_view();
ClickOrPressOnView(desk_name_view);
ASSERT_TRUE(desk_name_view->HasFocus());
PressAndReleaseKey(ui::VKEY_D, ui::EF_SHIFT_DOWN);
PressAndReleaseKey(ui::VKEY_1);
gfx::Point empty_point = desk_bar_view->GetBoundsInScreen().bottom_center();
empty_point.Offset(0, 2);
ClickOrPressOnPoint(empty_point);
EXPECT_FALSE(desk_name_view->HasFocus());
EXPECT_TRUE(desk->is_name_set_by_user());
EXPECT_THAT(desk_name_view->GetText(), u"D1");
EXPECT_TRUE(GetDeskBarView());
CloseDeskBar();
}
TEST_P(DeskBarTest, AutoHideClickOrPress) {
OpenDeskBar();
auto* desk_bar_view = GetDeskBarView();
gfx::Point empty_point = desk_bar_view->GetBoundsInScreen().bottom_center();
empty_point.Offset(0, 2);
ClickOrPressOnPoint(empty_point);
EXPECT_FALSE(GetDeskBarView());
}
TEST_P(DeskBarTest, AutoHideKeyEsc) {
OpenDeskBar();
ASSERT_TRUE(GetDeskBarView());
PressAndReleaseKey(ui::VKEY_ESCAPE);
EXPECT_FALSE(GetDeskBarView());
}
TEST_P(DeskBarTest, AutoHideKeyBack) {
OpenDeskBar();
ASSERT_TRUE(GetDeskBarView());
PressAndReleaseKey(ui::VKEY_BROWSER_BACK);
EXPECT_FALSE(GetDeskBarView());
}
TEST_P(DeskBarTest, ForwardTabbing) {
AddSavedDeskEntry(desk_model(), base::Uuid::GenerateRandomV4(),
"saved_desk_1", base::Time::Now(),
DeskTemplateType::kSaveAndRecall);
for (size_t i = 2; i <= desks_util::GetMaxNumberOfDesks() - 1; i++) {
NewDesk();
}
auto* desk_controller = DesksController::Get();
ASSERT_EQ(desk_controller->GetNumberOfDesks(),
static_cast<int>(desks_util::GetMaxNumberOfDesks()) - 1);
const auto& window = CreateAppWindow();
desk_controller->SendToDeskAtIndex(window.get(), 0);
OpenDeskBar();
auto* desk_bar_view = GetDeskBarView();
ASSERT_TRUE(desk_bar_view);
if (bar_type_ == DeskBarViewBase::Type::kOverview) {
PressAndReleaseKey(ui::VKEY_TAB);
}
for (int i = 0; i < desk_controller->GetNumberOfDesks(); i++) {
auto* mini_view = desk_bar_view->mini_views()[i].get();
PressAndReleaseKey(ui::VKEY_TAB);
ASSERT_TRUE(mini_view->desk_preview()->HasFocus());
const bool expected_visibility =
i <= 7 && bar_type_ == DeskBarViewBase::Type::kDeskButton;
EXPECT_EQ(DesksTestApi::IsDeskShortcutViewVisible(mini_view),
expected_visibility);
if (i == 0) {
PressAndReleaseKey(ui::VKEY_TAB);
ASSERT_TRUE(mini_view->desk_action_view()->context_menu_button());
ASSERT_TRUE(
mini_view->desk_action_view()->context_menu_button()->HasFocus());
}
PressAndReleaseKey(ui::VKEY_TAB);
ASSERT_TRUE(mini_view->desk_action_view()->close_all_button()->HasFocus());
EXPECT_EQ(DesksTestApi::IsDeskShortcutViewVisible(mini_view),
expected_visibility);
PressAndReleaseKey(ui::VKEY_TAB);
ASSERT_TRUE(mini_view->desk_name_view()->HasFocus());
EXPECT_FALSE(DesksTestApi::IsDeskShortcutViewVisible(
desk_bar_view->mini_views()[i]));
}
PressAndReleaseKey(ui::VKEY_TAB);
ASSERT_TRUE(desk_bar_view->new_desk_button()->HasFocus());
PressAndReleaseKey(ui::VKEY_TAB);
ASSERT_TRUE(desk_bar_view->library_button());
ASSERT_TRUE(desk_bar_view->library_button()->HasFocus());
CloseDeskBar();
}
TEST_P(DeskBarTest, ReverseTabbing) {
AddSavedDeskEntry(desk_model(), base::Uuid::GenerateRandomV4(),
"saved_desk_1", base::Time::Now(),
DeskTemplateType::kSaveAndRecall);
for (size_t i = 2; i <= desks_util::GetMaxNumberOfDesks() - 1; i++) {
NewDesk();
}
auto* desk_controller = DesksController::Get();
ASSERT_EQ(desk_controller->GetNumberOfDesks(),
static_cast<int>(desks_util::GetMaxNumberOfDesks()) - 1);
const auto& window = CreateAppWindow();
desk_controller->SendToDeskAtIndex(window.get(), 0);
OpenDeskBar();
auto* desk_bar_view = GetDeskBarView();
ASSERT_TRUE(desk_bar_view);
if (bar_type_ == DeskBarViewBase::Type::kDeskButton) {
PressAndReleaseKey(ui::VKEY_TAB, ui::EF_SHIFT_DOWN);
}
PressAndReleaseKey(ui::VKEY_TAB, ui::EF_SHIFT_DOWN);
ASSERT_TRUE(desk_bar_view->library_button());
ASSERT_TRUE(desk_bar_view->library_button()->HasFocus());
PressAndReleaseKey(ui::VKEY_TAB, ui::EF_SHIFT_DOWN);
ASSERT_TRUE(desk_bar_view->new_desk_button()->HasFocus());
for (int i = desk_controller->GetNumberOfDesks() - 1; i >= 0; i--) {
auto* mini_view = desk_bar_view->mini_views()[i].get();
PressAndReleaseKey(ui::VKEY_TAB, ui::EF_SHIFT_DOWN);
ASSERT_TRUE(mini_view->desk_name_view()->HasFocus());
EXPECT_FALSE(DesksTestApi::IsDeskShortcutViewVisible(
desk_bar_view->mini_views()[i]));
PressAndReleaseKey(ui::VKEY_TAB, ui::EF_SHIFT_DOWN);
ASSERT_TRUE(mini_view->desk_action_view()->close_all_button()->HasFocus());
if (i == 0) {
PressAndReleaseKey(ui::VKEY_TAB, ui::EF_SHIFT_DOWN);
ASSERT_TRUE(mini_view->desk_action_view()->context_menu_button());
ASSERT_TRUE(
mini_view->desk_action_view()->context_menu_button()->HasFocus());
}
const bool expected_visibility =
i <= 7 && bar_type_ == DeskBarViewBase::Type::kDeskButton;
EXPECT_EQ(DesksTestApi::IsDeskShortcutViewVisible(mini_view),
expected_visibility);
PressAndReleaseKey(ui::VKEY_TAB, ui::EF_SHIFT_DOWN);
ASSERT_TRUE(mini_view->desk_preview()->HasFocus());
EXPECT_EQ(DesksTestApi::IsDeskShortcutViewVisible(mini_view),
expected_visibility);
}
CloseDeskBar();
}
TEST_P(DeskBarTest, CloseActiveDesk) {
WindowHolder window_holder(CreateAppWindow());
NewDesk();
NewDesk();
auto* desks_controller = DesksController::Get();
desks_controller->desks()[0]->MoveWindowToDesk(
window_holder.window(), desks_controller->desks()[1].get(),
window_holder.window()->GetRootWindow(), true);
ActivateDesk(desks_controller->desks()[1].get());
OpenDeskBar();
auto* desk_bar_view = GetDeskBarView();
ASSERT_TRUE(desk_bar_view);
ASSERT_TRUE(TabUntil(
false,
ViewFocused(desk_bar_view->mini_views()[1]->desk_preview()),
GetEventGenerator()));
if (bar_type_ == DeskBarViewBase::Type::kOverview) {
PressAndReleaseKey(ui::VKEY_W, ui::EF_CONTROL_DOWN | ui::EF_SHIFT_DOWN);
EXPECT_TRUE(GetDeskBarView());
CloseDeskBar();
} else {
DeskSwitchAnimationWaiter waiter;
PressAndReleaseKey(ui::VKEY_W, ui::EF_CONTROL_DOWN | ui::EF_SHIFT_DOWN);
waiter.Wait();
EXPECT_FALSE(GetDeskBarView());
}
EXPECT_THAT(desks_controller->GetActiveDeskIndex(), 0);
EXPECT_THAT(desks_controller->desks().size(), 2);
SimulateWaitForCloseAll();
EXPECT_FALSE(window_holder.is_valid());
}
TEST_P(DeskBarTest, MergeActiveDesk) {
WindowHolder window_holder(CreateAppWindow());
NewDesk();
NewDesk();
auto* desks_controller = DesksController::Get();
desks_controller->desks()[0]->MoveWindowToDesk(
window_holder.window(), desks_controller->desks()[1].get(),
window_holder.window()->GetRootWindow(), true);
ActivateDesk(desks_controller->desks()[1].get());
OpenDeskBar();
auto* desk_bar_view = GetDeskBarView();
ASSERT_TRUE(desk_bar_view);
ASSERT_TRUE(TabUntil(
false,
ViewFocused(desk_bar_view->mini_views()[1]->desk_preview()),
GetEventGenerator()));
if (bar_type_ == DeskBarViewBase::Type::kOverview) {
PressAndReleaseKey(ui::VKEY_W, ui::EF_CONTROL_DOWN);
EXPECT_TRUE(GetDeskBarView());
CloseDeskBar();
} else {
DeskSwitchAnimationWaiter waiter;
PressAndReleaseKey(ui::VKEY_W, ui::EF_CONTROL_DOWN);
waiter.Wait();
EXPECT_FALSE(GetDeskBarView());
}
EXPECT_THAT(desks_controller->GetActiveDeskIndex(), 0);
EXPECT_THAT(desks_controller->desks().size(), 2);
EXPECT_TRUE(window_holder.is_valid());
EXPECT_TRUE(desks_controller->desks()[0]
->GetDeskContainerForRoot(Shell::GetPrimaryRootWindow())
->Contains(window_holder.window()));
}
TEST_P(DeskBarTest, CloseNonActiveDesk) {
WindowHolder window_holder(CreateAppWindow());
NewDesk();
NewDesk();
auto* desks_controller = DesksController::Get();
desks_controller->desks()[0]->MoveWindowToDesk(
window_holder.window(), desks_controller->desks()[1].get(),
window_holder.window()->GetRootWindow(), true);
OpenDeskBar();
auto* desk_bar_view = GetDeskBarView();
ASSERT_TRUE(desk_bar_view);
ASSERT_TRUE(TabUntil(
false,
ViewFocused(desk_bar_view->mini_views()[1]->desk_preview()),
GetEventGenerator()));
PressAndReleaseKey(ui::VKEY_W, ui::EF_CONTROL_DOWN | ui::EF_SHIFT_DOWN);
EXPECT_TRUE(GetDeskBarView());
EXPECT_THAT(desks_controller->GetActiveDeskIndex(), 0);
EXPECT_THAT(desks_controller->desks().size(), 2);
SimulateWaitForCloseAll();
EXPECT_FALSE(window_holder.is_valid());
CloseDeskBar();
}
TEST_P(DeskBarTest, MergeNonActiveDesk) {
WindowHolder window_holder(CreateAppWindow());
NewDesk();
NewDesk();
auto* desks_controller = DesksController::Get();
desks_controller->desks()[0]->MoveWindowToDesk(
window_holder.window(), desks_controller->desks()[1].get(),
window_holder.window()->GetRootWindow(), true);
OpenDeskBar();
auto* desk_bar_view = GetDeskBarView();
ASSERT_TRUE(desk_bar_view);
ASSERT_TRUE(TabUntil(
false,
ViewFocused(desk_bar_view->mini_views()[1]->desk_preview()),
GetEventGenerator()));
PressAndReleaseKey(ui::VKEY_W, ui::EF_CONTROL_DOWN);
EXPECT_TRUE(GetDeskBarView());
EXPECT_THAT(desks_controller->GetActiveDeskIndex(), 0);
EXPECT_THAT(desks_controller->desks().size(), 2);
EXPECT_TRUE(window_holder.is_valid());
EXPECT_TRUE(desks_controller->desks()[0]
->GetDeskContainerForRoot(Shell::GetPrimaryRootWindow())
->Contains(window_holder.window()));
CloseDeskBar();
}
TEST_P(DeskBarTest, DeskBarActionMetrics) {
NewDesk();
AddSavedDeskEntry(desk_model(), base::Uuid::GenerateRandomV4(),
"saved_desk_1", base::Time::Now(),
DeskTemplateType::kSaveAndRecall);
base::HistogramTester histogram_tester;
WindowHolder window(CreateAppWindow());
auto* desks_controller = DesksController::Get();
desks_controller->SendToDeskAtIndex(window.window(), 1);
OpenDeskBar();
auto* desk_bar_view = GetDeskBarView();
ClickOrPressOnView(desk_bar_view->new_desk_button());
views::test::RunScheduledLayout(desk_bar_view);
histogram_tester.ExpectTotalCount(
bar_type_ == DeskBarViewBase::Type::kDeskButton
? kDeskButtonDeskBarNewDeskHistogramName
: kOverviewDeskBarNewDeskHistogramName,
1);
PressAndReleaseKey(ui::VKEY_A, ui::EF_NONE);
PressAndReleaseKey(ui::VKEY_B, ui::EF_NONE);
PressAndReleaseKey(ui::VKEY_C, ui::EF_NONE);
PressAndReleaseKey(ui::VKEY_RETURN, ui::EF_NONE);
views::test::RunScheduledLayout(desk_bar_view);
histogram_tester.ExpectTotalCount(
bar_type_ == DeskBarViewBase::Type::kDeskButton
? kDeskButtonDeskBarRenameDeskHistogramName
: kOverviewDeskBarRenameDeskHistogramName,
1);
DeskSwitchAnimationWaiter waiter;
ClickOrPressOnView(desk_bar_view->mini_views()[2]->desk_preview());
waiter.Wait();
histogram_tester.ExpectTotalCount(
bar_type_ == DeskBarViewBase::Type::kDeskButton
? kDeskButtonDeskBarActivateDeskHistogramName
: kOverviewDeskBarActivateDeskHistogramName,
1);
OpenDeskBar();
desk_bar_view = GetDeskBarView();
const auto& mini_views = desk_bar_view->mini_views();
auto* event_generator = GetEventGenerator();
StartDragDeskPreview(mini_views[0], event_generator);
EXPECT_TRUE(desk_bar_view->IsDraggingDesk());
event_generator->MoveMouseTo(
mini_views[2]->GetPreviewBoundsInScreen().CenterPoint());
event_generator->ReleaseLeftButton();
views::test::RunScheduledLayout(desk_bar_view);
EXPECT_FALSE(desk_bar_view->IsDraggingDesk());
histogram_tester.ExpectTotalCount(
bar_type_ == DeskBarViewBase::Type::kDeskButton
? kDeskButtonDeskBarReorderDeskHistogramName
: kOverviewDeskBarReorderDeskHistogramName,
1);
auto* root_window = Shell::Get()->GetPrimaryRootWindow();
CombineDeskWithMenu(0, root_window, bar_type_);
histogram_tester.ExpectTotalCount(
bar_type_ == DeskBarViewBase::Type::kDeskButton
? kDeskButtonDeskBarCombineDesksHistogramName
: kOverviewDeskBarCombineDesksHistogramName,
1);
CloseDeskWithButton(1, true, root_window, bar_type_);
histogram_tester.ExpectTotalCount(
bar_type_ == DeskBarViewBase::Type::kDeskButton
? kDeskButtonDeskBarCloseDeskHistogramName
: kOverviewDeskBarCloseDeskHistogramName,
1);
EnterLibrary();
histogram_tester.ExpectTotalCount(
bar_type_ == DeskBarViewBase::Type::kDeskButton
? kDeskButtonDeskBarOpenLibraryHistogramName
: kOverviewDeskBarOpenLibraryHistogramName,
1);
}
TEST_P(DeskBarTest, DeskBarSwitchMetrics) {
NewDesk();
NewDesk();
base::HistogramTester histogram_tester;
WindowHolder window(CreateAppWindow());
auto* desks_controller = DesksController::Get();
desks_controller->SendToDeskAtIndex(window.window(), 0);
OpenDeskBar();
DeskSwitchAnimationWaiter waiter;
ClickOrPressOnView(GetDeskBarView()->mini_views()[1]->desk_preview());
waiter.Wait();
ASSERT_TRUE(desks_controller->desks()[1]->is_active());
histogram_tester.ExpectBucketCount(
kDeskSwitchHistogramName,
bar_type_ == DeskBarViewBase::Type::kDeskButton
? DesksSwitchSource::kDeskButtonMiniViewButton
: DesksSwitchSource::kMiniViewButton,
1);
OpenDeskBar();
auto* root_window = Shell::Get()->GetPrimaryRootWindow();
CloseDeskWithButton(1, true, root_window, bar_type_);
histogram_tester.ExpectBucketCount(
kDeskSwitchHistogramName,
bar_type_ == DeskBarViewBase::Type::kDeskButton
? DesksSwitchSource::kDeskButtonDeskRemoved
: DesksSwitchSource::kDeskRemoved,
1);
OpenDeskBar();
CombineDeskWithMenu(0, root_window, bar_type_);
histogram_tester.ExpectBucketCount(
kDeskSwitchHistogramName,
bar_type_ == DeskBarViewBase::Type::kDeskButton
? DesksSwitchSource::kDeskButtonDeskRemoved
: DesksSwitchSource::kDeskRemoved,
2);
}
TEST_P(DeskBarTest, DeskCreationRemovalMetrics) {
NewDesk();
base::HistogramTester histogram_tester;
WindowHolder window(CreateAppWindow());
auto* desks_controller = DesksController::Get();
desks_controller->SendToDeskAtIndex(window.window(), 0);
OpenDeskBar();
auto* desk_bar = GetDeskBarView();
ClickOrPressOnView(desk_bar->new_desk_button());
histogram_tester.ExpectBucketCount(
kNewDeskHistogramName,
bar_type_ == DeskBarViewBase::Type::kDeskButton
? DesksCreationRemovalSource::kDeskButtonDeskBarButton
: DesksCreationRemovalSource::kButton,
1);
auto* root_window = Shell::Get()->GetPrimaryRootWindow();
CloseDeskWithButton(1, true, root_window, bar_type_);
histogram_tester.ExpectBucketCount(
kRemoveDeskHistogramName,
bar_type_ == DeskBarViewBase::Type::kDeskButton
? DesksCreationRemovalSource::kDeskButtonDeskBarButton
: DesksCreationRemovalSource::kButton,
1);
CloseDeskBar();
OpenDeskBar();
CombineDeskWithMenu(0, root_window, bar_type_);
histogram_tester.ExpectBucketCount(
kRemoveDeskHistogramName,
bar_type_ == DeskBarViewBase::Type::kDeskButton
? DesksCreationRemovalSource::kDeskButtonDeskBarButton
: DesksCreationRemovalSource::kButton,
2);
}
TEST_P(DeskBarTest, DeskOpenContextMenuMetrics) {
NewDesk();
base::HistogramTester histogram_tester;
WindowHolder window(CreateAppWindow());
auto* desks_controller = DesksController::Get();
desks_controller->SendToDeskAtIndex(window.window(), 0);
OpenDeskBar();
auto* desk_bar = GetDeskBarView();
RightClickOn(desk_bar->mini_views()[0]);
EnterOverview();
auto* overview_desks_bar =
GetOverviewGridForRoot(Shell::GetPrimaryRootWindow())->desks_bar_view();
RightClickOn(overview_desks_bar->mini_views()[0]);
histogram_tester.ExpectTotalCount(
bar_type_ == DeskBarViewBase::Type::kDeskButton
? kDeskButtonDeskBarOpenContextMenuHistogramName
: kOverviewDeskBarOpenContextMenuHistogramName,
1);
}
TEST_P(DeskBarTest, BottomLockedShelf) {
OpenDeskBar();
GetPrimaryShelf()->SetAlignment(ShelfAlignment::kBottomLocked);
}
TEST_P(DeskBarTest, CanUndoDeskClosureThroughKeyboardNavigation) {
enum class DeskRemovalMethod {
kInactiveDeskRemovedForwardTab,
kInactiveDeskRemovedReverseTab,
kActiveDeskRemoved,
};
struct {
const std::string scope_trace;
const DeskRemovalMethod desk_removal_method;
} kTestCases[] = {
{"Forward tabbing to the undo button after removing an inactive desk",
DeskRemovalMethod::kInactiveDeskRemovedForwardTab},
{"Reverse tabbing to the undo button after removing an inactive desk",
DeskRemovalMethod::kInactiveDeskRemovedReverseTab},
{"Activating the undo button after removing the active desk",
DeskRemovalMethod::kActiveDeskRemoved},
};
NewDesk();
NewDesk();
Shell::Get()->accessibility_controller()->spoken_feedback().SetEnabled(true);
OpenDeskBar();
auto* desk_bar = GetDeskBarView();
const auto& mini_views = desk_bar->mini_views();
DesksController* desks_controller = DesksController::Get();
for (const auto& test_case : kTestCases) {
SCOPED_TRACE(test_case.scope_trace);
PressAndReleaseKey(ui::VKEY_TAB);
if (test_case.desk_removal_method !=
DeskRemovalMethod::kActiveDeskRemoved) {
PressAndReleaseKey(ui::VKEY_TAB);
PressAndReleaseKey(ui::VKEY_TAB);
PressAndReleaseKey(ui::VKEY_TAB);
ASSERT_TRUE(mini_views[1]->desk_preview()->HasFocus());
PressAndReleaseKey(ui::VKEY_W, ui::EF_CONTROL_DOWN | ui::EF_SHIFT_DOWN);
} else if (bar_type_ == DeskBarViewBase::Type::kDeskButton) {
ASSERT_EQ(mini_views[0]->desk_preview(),
desk_bar->GetWidget()->GetFocusManager()->GetFocusedView());
DeskSwitchAnimationWaiter waiter;
PressAndReleaseKey(ui::VKEY_W, ui::EF_CONTROL_DOWN | ui::EF_SHIFT_DOWN);
waiter.Wait();
} else {
ASSERT_EQ(DeskBarViewBase::Type::kOverview, bar_type_);
ASSERT_TRUE(mini_views[0]->desk_preview()->HasFocus());
PressAndReleaseKey(ui::VKEY_W, ui::EF_CONTROL_DOWN | ui::EF_SHIFT_DOWN);
}
ASSERT_EQ(2u, desks_controller->desks().size());
ASSERT_TRUE(TabUntil(
test_case.desk_removal_method ==
DeskRemovalMethod::kInactiveDeskRemovedReverseTab,
[desks_controller] { return desks_controller->IsUndoToastFocused(); },
GetEventGenerator()));
if (test_case.desk_removal_method ==
DeskRemovalMethod::kActiveDeskRemoved &&
bar_type_ == DeskBarViewBase::Type::kDeskButton) {
DeskSwitchAnimationWaiter waiter;
PressAndReleaseKey(ui::VKEY_RETURN);
waiter.Wait();
} else {
PressAndReleaseKey(ui::VKEY_RETURN);
}
ASSERT_EQ(3u, desks_controller->desks().size());
}
}
TEST_P(DeskBarTest, DeskActionButtonTooltipForNewDesk) {
OpenDeskBar();
auto* desk_bar_view = GetDeskBarView();
ClickOrPressOnView(desk_bar_view->new_desk_button());
views::test::RunScheduledLayout(desk_bar_view);
auto* desk_action_view = desk_bar_view->mini_views()[1]->desk_action_view();
EXPECT_TRUE(desk_action_view->context_menu_button());
EXPECT_THAT(desk_action_view->context_menu_button()->GetTooltipText(),
u"Open context menu");
EXPECT_THAT(desk_action_view->close_all_button()->GetTooltipText(),
u"Close Desk 2 and windows");
PressAndReleaseKey(ui::VKEY_D, ui::EF_SHIFT_DOWN);
PressAndReleaseKey(ui::VKEY_2);
PressAndReleaseKey(ui::VKEY_RETURN);
views::test::RunScheduledLayout(desk_bar_view);
EXPECT_TRUE(desk_action_view->context_menu_button());
EXPECT_THAT(desk_action_view->context_menu_button()->GetTooltipText(),
u"Open context menu");
EXPECT_THAT(desk_action_view->close_all_button()->GetTooltipText(),
u"Close D2 and windows");
CloseDeskBar();
}
struct DeskButtonTestParams {
ShelfAlignment alignment = ShelfAlignment::kBottom;
};
class DeskButtonTest
: public AshTestBase,
public ::testing::WithParamInterface<DeskButtonTestParams> {
public:
DeskButtonTest() = default;
DeskButtonTest(const DeskButtonTest&) = delete;
DeskButtonTest& operator=(const DeskButtonTest&) = delete;
~DeskButtonTest() override = default;
void SetUp() override {
AshTestBase::SetUp();
shelf_test_api_ = std::make_unique<ShelfViewTestAPI>(
GetPrimaryShelf()->GetShelfViewForTesting());
GetPrimaryShelf()->SetAlignment(GetParam().alignment);
SetShowDeskButtonInShelfPref(GetPrimaryUserPrefService(), true);
SetShelfAlignmentPref(GetPrimaryUserPrefService(), GetPrimaryDisplay().id(),
GetParam().alignment);
}
DeskButtonWidget* GetDeskButtonWidget() {
return GetPrimaryShelf()->shelf_widget()->desk_button_widget();
}
DeskButton* GetDeskButton() {
return GetDeskButtonWidget()->GetDeskButtonContainer()->desk_button();
}
DeskSwitchButton* GetPrevDeskButton() {
return GetDeskButtonWidget()->GetDeskButtonContainer()->prev_desk_button();
}
DeskSwitchButton* GetNextDeskButton() {
return GetDeskButtonWidget()->GetDeskButtonContainer()->next_desk_button();
}
void SwitchToAdjacentDesk(bool next) {
if (GetParam().alignment == ShelfAlignment::kBottom) {
auto* event_generator = GetEventGenerator();
auto* desk_button = GetDeskButton();
ASSERT_TRUE(desk_button);
event_generator->MoveMouseTo(
desk_button->GetBoundsInScreen().CenterPoint());
views::ImageButton* target_button =
next ? GetNextDeskButton() : GetPrevDeskButton();
ASSERT_TRUE(target_button);
EXPECT_TRUE(target_button->GetVisible());
EXPECT_TRUE(target_button->GetEnabled());
event_generator->MoveMouseTo(
target_button->GetBoundsInScreen().CenterPoint());
DeskSwitchAnimationWaiter waiter;
event_generator->ClickLeftButton();
waiter.Wait();
} else {
DeskSwitchAnimationWaiter waiter;
PressAndReleaseKey(next ? ui::VKEY_OEM_6 : ui::VKEY_OEM_4,
ui::EF_COMMAND_DOWN);
waiter.Wait();
}
}
void ClickDeskButton() {
HoverDeskButton();
auto* event_generator = GetEventGenerator();
auto* desk_button = GetDeskButton();
ASSERT_TRUE(desk_button);
event_generator->MoveMouseTo(
desk_button->GetBoundsInScreen().CenterPoint());
event_generator->ClickLeftButton();
}
void HoverDeskButton() {
auto* event_generator = GetEventGenerator();
auto* desk_button = GetDeskButton();
ASSERT_TRUE(desk_button);
event_generator->MoveMouseTo(
desk_button->GetBoundsInScreen().CenterPoint());
if (!desk_button->zero_state()) {
ASSERT_EQ(GetParam().alignment, ShelfAlignment::kBottom);
}
}
void UnhoverDeskButton() {
auto* event_generator = GetEventGenerator();
event_generator->MoveMouseTo(0, 0);
}
void OpenDeskBar() {
DesksController::Get()->desk_bar_controller()->OpenDeskBar(
Shell::Get()->GetPrimaryRootWindow());
}
void CloseDeskBar() {
DesksController::Get()->desk_bar_controller()->CloseDeskBar(
Shell::Get()->GetPrimaryRootWindow());
}
DeskBarViewBase* GetDeskBarView() {
return DesksController::Get()->desk_bar_controller()->GetDeskBarView(
Shell::Get()->GetPrimaryRootWindow());
}
private:
std::unique_ptr<ShelfViewTestAPI> shelf_test_api_;
};
TEST_P(DeskButtonTest, AccessiblePrevAndNextFocusWindow) {
NewDesk();
views::test::RunScheduledLayout(GetDeskButtonWidget());
auto* desk_button = GetDeskButton();
auto* shelf_widget =
Shelf::ForWindow(desk_button->GetWidget()->GetNativeWindow())
->shelf_widget();
EXPECT_EQ(desk_button->GetViewAccessibility().GetPreviousWindowFocus(),
shelf_widget->navigation_widget());
EXPECT_EQ(desk_button->GetViewAccessibility().GetNextWindowFocus(),
shelf_widget);
}
TEST_P(DeskButtonTest, DeskSwitchButtons) {
views::ImageButton* prev_desk_button = GetPrevDeskButton();
views::ImageButton* next_desk_button = GetNextDeskButton();
ASSERT_TRUE(prev_desk_button);
ASSERT_TRUE(next_desk_button);
EXPECT_FALSE(prev_desk_button->GetVisible());
EXPECT_FALSE(next_desk_button->GetVisible());
NewDesk();
views::test::RunScheduledLayout(GetDeskButtonWidget());
if (GetParam().alignment == ShelfAlignment::kBottom) {
EXPECT_FALSE(prev_desk_button->GetVisible());
EXPECT_TRUE(next_desk_button->GetVisible());
EXPECT_TRUE(next_desk_button->GetEnabled());
} else {
EXPECT_FALSE(prev_desk_button->GetVisible());
EXPECT_FALSE(next_desk_button->GetVisible());
}
SwitchToAdjacentDesk(true);
if (GetParam().alignment == ShelfAlignment::kBottom) {
EXPECT_TRUE(prev_desk_button->GetVisible());
EXPECT_TRUE(prev_desk_button->GetEnabled());
EXPECT_TRUE(next_desk_button->GetVisible());
EXPECT_FALSE(next_desk_button->GetEnabled());
} else {
EXPECT_FALSE(prev_desk_button->GetVisible());
EXPECT_FALSE(next_desk_button->GetVisible());
}
NewDesk();
views::test::RunScheduledLayout(GetDeskButtonWidget());
if (GetParam().alignment == ShelfAlignment::kBottom) {
EXPECT_TRUE(prev_desk_button->GetVisible());
EXPECT_TRUE(prev_desk_button->GetEnabled());
EXPECT_TRUE(next_desk_button->GetVisible());
EXPECT_TRUE(next_desk_button->GetEnabled());
} else {
EXPECT_FALSE(prev_desk_button->GetVisible());
EXPECT_FALSE(next_desk_button->GetVisible());
}
SwitchToAdjacentDesk(true);
if (GetParam().alignment == ShelfAlignment::kBottom) {
EXPECT_TRUE(prev_desk_button->GetVisible());
EXPECT_TRUE(prev_desk_button->GetEnabled());
EXPECT_TRUE(next_desk_button->GetVisible());
EXPECT_FALSE(next_desk_button->GetEnabled());
} else {
EXPECT_FALSE(prev_desk_button->GetVisible());
EXPECT_FALSE(next_desk_button->GetVisible());
}
SwitchToAdjacentDesk(false);
if (GetParam().alignment == ShelfAlignment::kBottom) {
EXPECT_TRUE(prev_desk_button->GetVisible());
EXPECT_TRUE(prev_desk_button->GetEnabled());
EXPECT_TRUE(next_desk_button->GetVisible());
EXPECT_TRUE(next_desk_button->GetEnabled());
} else {
EXPECT_FALSE(prev_desk_button->GetVisible());
EXPECT_FALSE(next_desk_button->GetVisible());
}
}
TEST_P(DeskButtonTest, DeskButtonTextReflectsDeskChange) {
UpdateDisplay("1280x720");
NewDesk();
auto* controller = DesksController::Get();
auto* desk_1 = controller->GetDeskAtIndex(0);
auto* desk_2 = controller->GetDeskAtIndex(1);
ASSERT_TRUE(desk_1->is_active());
desk_1->SetName(u"Work", true);
auto* desk_button = GetDeskButton();
ASSERT_TRUE(desk_button);
EXPECT_EQ(GetParam().alignment == ShelfAlignment::kBottom ? u"Work" : u"W",
desk_button->desk_name_label()->GetText());
views::test::RunScheduledLayout(desk_button);
desk_2->SetName(u"Fun", true);
EXPECT_EQ(GetParam().alignment == ShelfAlignment::kBottom ? u"Work" : u"W",
desk_button->desk_name_label()->GetText());
SwitchToAdjacentDesk(true);
EXPECT_EQ(GetParam().alignment == ShelfAlignment::kBottom ? u"Fun" : u"F",
desk_button->desk_name_label()->GetText());
NewDesk();
SwitchToAdjacentDesk(true);
EXPECT_EQ(GetParam().alignment == ShelfAlignment::kBottom ? u"Desk 3" : u"#3",
desk_button->desk_name_label()->GetText());
}
TEST_P(DeskButtonTest, DeskButtonTextWorksWithEmojis) {
UpdateDisplay("1280x720");
NewDesk();
auto* controller = DesksController::Get();
controller->GetDeskAtIndex(0)->SetName(u"😃emoji", true);
auto* desk_button = GetDeskButton();
ASSERT_TRUE(desk_button);
EXPECT_EQ(
GetParam().alignment == ShelfAlignment::kBottom ? u"😃emoji" : u"😃",
desk_button->desk_name_label()->GetText());
}
TEST_P(DeskButtonTest, OverviewDeskSwitch) {
NewDesk();
EXPECT_TRUE(GetDeskButtonWidget()->GetLayer()->GetTargetVisibility());
EnterOverview();
EXPECT_FALSE(GetDeskButtonWidget()->GetLayer()->GetTargetVisibility());
auto* desks_controller = DesksController::Get();
ActivateDesk(desks_controller->GetDeskAtIndex(1));
EXPECT_TRUE(GetDeskButtonWidget()->GetLayer()->GetTargetVisibility());
}
TEST_P(DeskButtonTest, UpdateShelfAlignmentDuringTest) {
UpdateDisplay("1280x720");
NewDesk();
DesksController::Get()->GetDeskAtIndex(0)->SetName(u"school",
true);
const bool bottom_at_start = GetParam().alignment == ShelfAlignment::kBottom;
auto* desk_button = GetDeskButton();
ASSERT_TRUE(desk_button);
ASSERT_EQ(bottom_at_start ? u"school" : u"s",
desk_button->desk_name_label()->GetText());
ASSERT_EQ(bottom_at_start ? cros_tokens::kCrosSysSystemOnBase1
: cros_tokens::kCrosSysSystemOnBase,
desk_button->GetBackground()->color());
ClickDeskButton();
ASSERT_EQ(cros_tokens::kCrosSysSystemPrimaryContainer,
desk_button->GetBackground()->color());
ClickDeskButton();
ASSERT_EQ(bottom_at_start ? cros_tokens::kCrosSysSystemOnBase1
: cros_tokens::kCrosSysSystemOnBase,
desk_button->GetBackground()->color());
GetPrimaryShelf()->SetAlignment(bottom_at_start ? ShelfAlignment::kLeft
: ShelfAlignment::kBottom);
ASSERT_EQ(bottom_at_start ? cros_tokens::kCrosSysSystemOnBase
: cros_tokens::kCrosSysSystemOnBase1,
desk_button->GetBackground()->color());
EXPECT_EQ(bottom_at_start ? u"s" : u"school",
desk_button->desk_name_label()->GetText());
}
TEST_P(DeskButtonTest, SuspendShelfAutoHideWhenActivated) {
auto* shelf = GetPrimaryShelf();
shelf->SetAutoHideBehavior(ShelfAutoHideBehavior::kAlways);
ASSERT_FALSE(shelf->disable_auto_hide());
auto* desk_button = GetDeskButton();
ASSERT_TRUE(desk_button);
ClickDeskButton();
UnhoverDeskButton();
EXPECT_TRUE(desk_button->is_activated());
EXPECT_NE(desk_button->GetState(), views::Button::ButtonState::STATE_HOVERED);
EXPECT_TRUE(shelf->disable_auto_hide());
ClickDeskButton();
UnhoverDeskButton();
EXPECT_FALSE(desk_button->is_activated());
EXPECT_NE(desk_button->GetState(), views::Button::ButtonState::STATE_HOVERED);
ASSERT_FALSE(shelf->disable_auto_hide());
}
TEST_P(DeskButtonTest, ValidateDeskButtonPosition) {
UpdateDisplay("1280x720");
NewDesk();
NewDesk();
auto* desk_button = GetDeskButton();
auto* prev_desk_button = GetPrevDeskButton();
auto* next_desk_button = GetNextDeskButton();
auto* desk_name_label = desk_button->desk_name_label();
auto* desk_controller = DesksController::Get();
const int desk_count = desk_controller->GetNumberOfDesks();
for (int i = desk_count - 1; i >= 0; i--) {
ActivateDesk(desk_controller->desks()[i].get());
const bool should_show_prev_desk_button =
GetParam().alignment == ShelfAlignment::kBottom && i > 0;
const bool should_show_next_desk_button =
GetParam().alignment == ShelfAlignment::kBottom;
const bool should_enable_next_desk_button =
GetParam().alignment == ShelfAlignment::kBottom && i < desk_count - 1;
if (GetParam().alignment == ShelfAlignment::kBottom) {
EXPECT_TRUE(gfx::Rect(4, 4, 128, 28).Contains(desk_button->bounds()));
EXPECT_TRUE(
gfx::Rect(10, 0, 102, 28).Contains(desk_name_label->bounds()));
} else {
EXPECT_EQ(desk_button->bounds(), gfx::Rect(0, 0, 36, 36));
EXPECT_EQ(desk_name_label->bounds(), gfx::Rect(4, 4, 28, 28));
}
EXPECT_EQ(prev_desk_button->GetVisible(), should_show_prev_desk_button);
if (prev_desk_button->GetVisible()) {
EXPECT_TRUE(prev_desk_button->GetEnabled());
}
EXPECT_EQ(next_desk_button->GetVisible(), should_show_next_desk_button);
if (next_desk_button->GetVisible()) {
EXPECT_EQ(next_desk_button->GetEnabled(), should_enable_next_desk_button);
}
}
}
TEST_P(DeskButtonTest, DeskButtonPressMetrics) {
NewDesk();
base::HistogramTester histogram_tester;
ClickDeskButton();
histogram_tester.ExpectTotalCount(kDeskButtonPressesHistogramName, 1);
ClickDeskButton();
histogram_tester.ExpectTotalCount(kDeskButtonPressesHistogramName, 2);
}
TEST_P(DeskButtonTest, LayoutInRTL) {
base::i18n::ScopedRTLForTesting scoped_rtl(true);
EXPECT_TRUE(base::i18n::IsRTL());
GetDeskButtonWidget()->HandleLocaleChange();
GetPrimaryShelf()->shelf_layout_manager()->LayoutShelf();
UpdateDisplay("1280x720");
SkBitmap app_bitmap;
app_bitmap.allocN32Pixels(1, 1);
app_bitmap.eraseColor(SK_ColorRED);
ShelfTestUtil::AddAppShortcutWithIcon(
"0", TYPE_PINNED_APP, gfx::ImageSkia::CreateFrom1xBitmap(app_bitmap));
NewDesk();
NewDesk();
views::test::RunScheduledLayout(GetDeskButtonWidget());
SwitchToAdjacentDesk(true);
const gfx::Rect desk_button_bounds = GetDeskButton()->GetBoundsInScreen();
const gfx::Rect app_icon_bounds = GetPrimaryShelf()
->hotseat_widget()
->GetShelfView()
->first_visible_button_for_testing()
->GetBoundsInScreen();
switch (GetParam().alignment) {
case ShelfAlignment::kBottom:
case ShelfAlignment::kBottomLocked:
EXPECT_TRUE(gfx::Rect(684, 682, 128, 28).Contains(desk_button_bounds));
EXPECT_LT(app_icon_bounds.x(), desk_button_bounds.x());
break;
case ShelfAlignment::kLeft:
EXPECT_EQ(gfx::Rect(6, 286, 36, 36), desk_button_bounds);
EXPECT_LT(desk_button_bounds.y(), app_icon_bounds.y());
break;
case ShelfAlignment::kRight:
EXPECT_EQ(gfx::Rect(1238, 286, 36, 36), desk_button_bounds);
EXPECT_LT(desk_button_bounds.y(), app_icon_bounds.y());
break;
}
auto* prev_desk_button = GetPrevDeskButton();
auto* next_desk_button = GetNextDeskButton();
if (GetParam().alignment == ShelfAlignment::kBottom) {
ASSERT_TRUE(prev_desk_button->GetVisible());
ASSERT_TRUE(prev_desk_button->GetEnabled());
ASSERT_TRUE(next_desk_button->GetVisible());
ASSERT_TRUE(next_desk_button->GetEnabled());
EXPECT_GT(prev_desk_button->GetBoundsInScreen().x(),
desk_button_bounds.right());
EXPECT_GT(next_desk_button->GetBoundsInScreen().x(),
prev_desk_button->GetBoundsInScreen().right());
} else {
ASSERT_FALSE(prev_desk_button->GetVisible());
ASSERT_FALSE(next_desk_button->GetVisible());
}
auto* desks_controller = DesksController::Get();
SwitchToAdjacentDesk(false);
EXPECT_EQ(0, desks_controller->GetActiveDeskIndex());
SwitchToAdjacentDesk(true);
SwitchToAdjacentDesk(true);
EXPECT_EQ(2, desks_controller->GetActiveDeskIndex());
}
TEST_P(DeskButtonTest, BarBoundsWithDeviceSacleFactorChange) {
for (auto key : {ui::VKEY_OEM_MINUS, ui::VKEY_OEM_PLUS}) {
OpenDeskBar();
PressAndReleaseKey(key, ui::EF_CONTROL_DOWN | ui::EF_SHIFT_DOWN);
ASSERT_TRUE(GetDeskBarView());
gfx::Rect bounds = GetDeskBarView()->GetWidget()->GetWindowBoundsInScreen();
CloseDeskBar();
OpenDeskBar();
gfx::Rect expected_bounds =
GetDeskBarView()->GetWidget()->GetWindowBoundsInScreen();
CloseDeskBar();
EXPECT_EQ(bounds, expected_bounds);
}
}
TEST_P(DeskButtonTest, BarBoundsWithScreenRotationChange) {
const int control_and_shift = ui::EF_CONTROL_DOWN | ui::EF_SHIFT_DOWN;
auto* accessibility_controller = Shell::Get()->accessibility_controller();
PressAndReleaseKey(ui::VKEY_BROWSER_REFRESH, control_and_shift);
if (auto* confirm_dialog =
accessibility_controller->GetConfirmationDialogForTest()) {
confirm_dialog->AcceptDialog();
base::RunLoop().RunUntilIdle();
}
for (int i = 0; i < 4; i++) {
OpenDeskBar();
PressAndReleaseKey(ui::VKEY_BROWSER_REFRESH, control_and_shift);
ASSERT_TRUE(GetDeskBarView());
gfx::Rect bounds = GetDeskBarView()->GetWidget()->GetWindowBoundsInScreen();
CloseDeskBar();
OpenDeskBar();
gfx::Rect expected_bounds =
GetDeskBarView()->GetWidget()->GetWindowBoundsInScreen();
CloseDeskBar();
EXPECT_EQ(bounds, expected_bounds);
}
}
TEST_P(DeskButtonTest, BarBoundsWithWorkAreaChangeChromevox) {
const int control_and_alt = ui::EF_CONTROL_DOWN | ui::EF_ALT_DOWN;
OpenDeskBar();
PressAndReleaseKey(ui::VKEY_Z, control_and_alt);
ASSERT_TRUE(GetDeskBarView());
gfx::Rect bounds = GetDeskBarView()->GetWidget()->GetWindowBoundsInScreen();
CloseDeskBar();
OpenDeskBar();
gfx::Rect expected_bounds =
GetDeskBarView()->GetWidget()->GetWindowBoundsInScreen();
CloseDeskBar();
PressAndReleaseKey(ui::VKEY_Z, control_and_alt);
EXPECT_EQ(bounds, expected_bounds);
}
TEST_P(DeskButtonTest, BarBoundsWithWorkAreaChangeDockedMagnifier) {
UpdateDisplay("1024x768");
const int control_and_search = ui::EF_CONTROL_DOWN | ui::EF_COMMAND_DOWN;
auto* accessibility_controller = Shell::Get()->accessibility_controller();
PressAndReleaseKey(ui::VKEY_D, control_and_search);
if (auto* confirm_dialog =
accessibility_controller->GetConfirmationDialogForTest()) {
confirm_dialog->AcceptDialog();
base::RunLoop().RunUntilIdle();
}
PressAndReleaseKey(ui::VKEY_D, control_and_search);
OpenDeskBar();
PressAndReleaseKey(ui::VKEY_D, control_and_search);
ASSERT_TRUE(GetDeskBarView());
gfx::Rect bounds = GetDeskBarView()->GetWidget()->GetWindowBoundsInScreen();
CloseDeskBar();
OpenDeskBar();
gfx::Rect expected_bounds =
GetDeskBarView()->GetWidget()->GetWindowBoundsInScreen();
CloseDeskBar();
PressAndReleaseKey(ui::VKEY_D, control_and_search);
EXPECT_EQ(bounds, expected_bounds);
}
TEST_P(DeskButtonTest, BarBoundsWithRTL) {
UpdateDisplay("800x600");
base::i18n::ScopedRTLForTesting scoped_rtl(true);
ASSERT_TRUE(base::i18n::IsRTL());
OpenDeskBar();
EXPECT_EQ(GetDeskBarView()->bounds(), gfx::Rect(0, 0, 154, 98));
CloseDeskBar();
}
TEST_P(DeskButtonTest, TabOrder) {
NewDesk();
NewDesk();
auto* desks_controller = DesksController::Get();
ASSERT_THAT(desks_controller->desks().size(), 3);
ASSERT_THAT(desks_controller->GetActiveDeskIndex(), 0);
PressAndReleaseKey(ui::VKEY_TAB);
if (GetParam().alignment == ShelfAlignment::kBottom) {
PressAndReleaseKey(ui::VKEY_TAB);
ASSERT_TRUE(GetDeskButton()->HasFocus());
PressAndReleaseKey(ui::VKEY_TAB);
ASSERT_TRUE(GetNextDeskButton()->HasFocus());
PressAndReleaseKey(ui::VKEY_TAB, ui::EF_SHIFT_DOWN);
ASSERT_TRUE(GetDeskButton()->HasFocus());
PressAndReleaseKey(ui::VKEY_TAB);
ASSERT_TRUE(GetNextDeskButton()->HasFocus());
DeskSwitchAnimationWaiter waiter;
PressAndReleaseKey(ui::VKEY_RETURN);
waiter.Wait();
ASSERT_THAT(desks_controller->GetActiveDeskIndex(), 1);
ASSERT_TRUE(GetPrevDeskButton()->GetEnabled());
ASSERT_TRUE(GetNextDeskButton()->GetEnabled());
DeskSwitchAnimationWaiter waiter2;
PressAndReleaseKey(ui::VKEY_RETURN);
waiter2.Wait();
ASSERT_THAT(desks_controller->GetActiveDeskIndex(), 2);
ASSERT_FALSE(GetNextDeskButton()->GetEnabled());
} else {
PressAndReleaseKey(ui::VKEY_TAB);
ASSERT_TRUE(GetDeskButton()->HasFocus());
ASSERT_TRUE(GetDeskButton()->zero_state());
PressAndReleaseKey(ui::VKEY_TAB);
ASSERT_FALSE(GetDeskButton()->HasFocus());
ASSERT_TRUE(GetDeskButton()->zero_state());
}
}
TEST_P(DeskButtonTest, BarAboveFloatWindow) {
std::unique_ptr<aura::Window> floated_window = CreateAppWindow();
PressAndReleaseKey(ui::VKEY_F, ui::EF_ALT_DOWN | ui::EF_COMMAND_DOWN);
ASSERT_TRUE(WindowState::Get(floated_window.get())->IsFloated());
OpenDeskBar();
auto* desk_bar_view = GetDeskBarView();
floated_window->SetBounds(desk_bar_view->GetBoundsInScreen());
EXPECT_EQ(
GetTopmostWindowAtPoint(desk_bar_view->GetBoundsInScreen().CenterPoint(),
{}),
desk_bar_view->GetWidget()->GetNativeWindow());
}
TEST_P(DeskButtonTest, SendFocusBackToDeskButton) {
PressAndReleaseKey(ui::VKEY_TAB);
PressAndReleaseKey(ui::VKEY_TAB);
ASSERT_TRUE(GetDeskButton()->HasFocus());
PressAndReleaseKey(ui::VKEY_RETURN);
ASSERT_TRUE(GetDeskBarView());
PressAndReleaseKey(ui::VKEY_ESCAPE);
ASSERT_TRUE(GetDeskButton()->HasFocus());
}
TEST_P(DeskButtonTest, DeskButtonContextMenu) {
for (bool use_touch_gestures : {false, true}) {
auto* event_generator = GetEventGenerator();
auto* desk_button = GetDeskButton();
if (use_touch_gestures) {
LongGestureTap(desk_button->GetBoundsInScreen().CenterPoint(),
event_generator);
} else {
RightClickOn(desk_button);
}
EXPECT_NE(desk_button->GetState(),
views::Button::ButtonState::STATE_HOVERED);
EXPECT_TRUE(GetPrimaryShelf()->GetShelfViewForTesting()->IsShowingMenu());
PressAndReleaseKey(ui::VKEY_ESCAPE);
EXPECT_FALSE(GetPrimaryShelf()->GetShelfViewForTesting()->IsShowingMenu());
ClickDeskButton();
if (use_touch_gestures) {
LongGestureTap(desk_button->GetBoundsInScreen().CenterPoint(),
event_generator);
} else {
RightClickOn(desk_button);
}
EXPECT_FALSE(GetPrimaryShelf()->GetShelfViewForTesting()->IsShowingMenu());
CloseDeskBar();
}
}
TEST_P(DeskButtonTest, DeskSwitchButtonContextMenu) {
if (GetParam().alignment != ShelfAlignment::kBottom) {
SUCCEED();
return;
}
NewDesk();
NewDesk();
struct DeskSwitchButtonTestCase {
bool visible;
bool enabled;
bool show_context_menu;
};
const auto prev_test_cases = std::to_array<DeskSwitchButtonTestCase>({
{.visible = false, .enabled = false, .show_context_menu = false},
{.visible = true, .enabled = true, .show_context_menu = true},
{.visible = true, .enabled = true, .show_context_menu = true},
});
const auto next_test_cases = std::to_array<DeskSwitchButtonTestCase>({
{.visible = true, .enabled = true, .show_context_menu = true},
{.visible = true, .enabled = true, .show_context_menu = true},
{.visible = true, .enabled = false, .show_context_menu = false},
});
auto* event_generator = GetEventGenerator();
auto* shelf_view = GetPrimaryShelf()->GetShelfViewForTesting();
auto verify_button = [&](DeskSwitchButton* button, bool button_visible,
bool button_enabled, bool button_show_context_menu,
bool use_touch_gestures, bool desk_bar_active) {
SCOPED_TRACE(
"Testing " +
(button->type() == DeskSwitchButton::Type::kPrev
? std::string("previous desk button")
: std::string("next desk button")) +
" in " +
base::UTF16ToUTF8(DesksController::Get()->active_desk()->name()) +
" using " +
(use_touch_gestures ? std::string("gestures") : std::string("mouse")) +
" when desk bar " +
(desk_bar_active ? std::string("active") : std::string("not active")));
ASSERT_EQ(button->GetVisible(), button_visible);
if (!button->GetVisible()) {
return;
}
EXPECT_EQ(button->GetEnabled(), button_enabled);
if (use_touch_gestures) {
LongGestureTap(button->GetBoundsInScreen().CenterPoint(),
event_generator);
} else {
RightClickOn(button);
}
views::test::RunScheduledLayout(button);
EXPECT_EQ(shelf_view->IsShowingMenu(), button_show_context_menu);
if (!desk_bar_active) {
EXPECT_NE(button->GetState(), views::Button::ButtonState::STATE_HOVERED);
}
if (shelf_view->IsShowingMenu()) {
PressAndReleaseKey(ui::VKEY_ESCAPE);
EXPECT_FALSE(shelf_view->IsShowingMenu());
}
};
for (bool use_touch_gestures : {false, true}) {
auto* desk_controller = DesksController::Get();
for (int index = 0; index < desk_controller->GetNumberOfDesks(); index++) {
if (desk_controller->GetActiveDeskIndex() != index) {
ActivateDesk(desk_controller->GetDeskAtIndex(index));
}
verify_button(GetPrevDeskButton(), prev_test_cases[index].visible,
prev_test_cases[index].enabled,
prev_test_cases[index].show_context_menu,
use_touch_gestures, false);
verify_button(GetNextDeskButton(), next_test_cases[index].visible,
next_test_cases[index].enabled,
next_test_cases[index].show_context_menu,
use_touch_gestures, false);
ClickDeskButton();
verify_button(GetPrevDeskButton(), prev_test_cases[index].visible,
prev_test_cases[index].enabled, false, use_touch_gestures,
true);
verify_button(GetNextDeskButton(), next_test_cases[index].visible,
next_test_cases[index].enabled, false, use_touch_gestures,
true);
CloseDeskBar();
}
}
}
TEST_P(DesksAcceleratorsTest, DeskSwitchScreenshotMetricsRecording) {
NewDesk();
base::HistogramTester histogram_tester;
histogram_tester.ExpectTotalCount(kDeskSwitchScreenshotResultHistogramName,
0);
DeskSwitchAnimationWaiter waiter;
SendAccelerator(ui::VKEY_OEM_6, ui::EF_COMMAND_DOWN);
waiter.Wait();
histogram_tester.ExpectTotalCount(kDeskSwitchScreenshotResultHistogramName,
2);
histogram_tester.ExpectBucketCount(kDeskSwitchScreenshotResultHistogramName,
true, 2);
}
TEST_P(DesksTest, DeskCreationBlockedDuringKioskSession) {
TestingPrefServiceSimple local_state;
user_manager::UserManager::RegisterPrefs(local_state.registry());
user_manager::ScopedUserManager user_manager(
std::make_unique<user_manager::FakeUserManager>(&local_state));
chromeos::SetUpFakeChromeAppKioskSession();
DesksController* desks_controller = DesksController::Get();
ASSERT_FALSE(desks_controller->CanCreateDesks());
}
constexpr DesksTestParams kTestCombinations[] = {
{.use_touch_gestures = false, .use_16_desks = false},
{.use_touch_gestures = false, .use_16_desks = true},
{.use_touch_gestures = true, .use_16_desks = false},
{.use_touch_gestures = true, .use_16_desks = true},
{.per_desk_shelf = true},
};
constexpr DesksTestParams kDeskCountOnly[] = {
{.use_16_desks = false},
{.use_16_desks = true},
};
std::string GetDeskCountSuffix(bool use_16_desks) {
return use_16_desks ? "16Desks" : "8Desks";
}
std::string GetTestSuffix(const DesksTestParams& params) {
std::string use_touch = params.use_touch_gestures ? "Touch" : "Mouse";
std::string use_16 = GetDeskCountSuffix(params.use_16_desks);
std::string use_per_desk_shelf =
params.per_desk_shelf ? "PerDeskShelf" : "NoPerDeskShelf";
return base::StringPrintf("%s_%s_%s", use_touch.c_str(), use_16.c_str(),
use_per_desk_shelf.c_str());
}
std::string GetDeskCountOnlyTestSuffix(
const testing::TestParamInfo<DesksTestParams>& info) {
return GetDeskCountSuffix(info.param.use_16_desks);
}
constexpr DeskButtonTestParams kDeskButtonTestParamCombinations[] = {
{.alignment = ShelfAlignment::kBottom},
{.alignment = ShelfAlignment::kLeft},
{.alignment = ShelfAlignment::kRight}};
INSTANTIATE_TEST_SUITE_P(
All,
DesksTest,
ValuesIn(kTestCombinations),
[](const testing::TestParamInfo<DesksTestParams>& info) {
return GetTestSuffix(info.param);
});
INSTANTIATE_TEST_SUITE_P(All,
DesksEditableNamesTest,
ValuesIn(kDeskCountOnly),
GetDeskCountOnlyTestSuffix);
INSTANTIATE_TEST_SUITE_P(All,
TabletModeDesksTest,
ValuesIn(kDeskCountOnly),
GetDeskCountOnlyTestSuffix);
INSTANTIATE_TEST_SUITE_P(All,
DesksAcceleratorsTest,
ValuesIn(kDeskCountOnly),
GetDeskCountOnlyTestSuffix);
INSTANTIATE_TEST_SUITE_P(All,
DesksMockTimeTest,
ValuesIn(kDeskCountOnly),
GetDeskCountOnlyTestSuffix);
INSTANTIATE_TEST_SUITE_P(All,
DesksCloseAllTest,
ValuesIn(kDeskCountOnly),
GetDeskCountOnlyTestSuffix);
INSTANTIATE_TEST_SUITE_P(All,
PerDeskShelfTest,
testing::Bool(),
[](const testing::TestParamInfo<bool>& info) {
return info.param ? "PerDeskShelfOn"
: "PerDeskShelfOff";
});
INSTANTIATE_TEST_SUITE_P(
All,
DeskBarTest,
testing::Combine(testing::Bool(),
testing::Bool(),
testing::Values(DeskBarViewBase::Type::kDeskButton,
DeskBarViewBase::Type::kOverview)),
[](const testing::TestParamInfo<DeskBarTest::ParamType>& info) {
DesksTestParams params;
DeskBarViewBase::Type bar_type;
std::tie(params.use_touch_gestures, params.use_16_desks, bar_type) =
info.param;
std::string result = GetTestSuffix(params);
std::string bar_type_str;
switch (bar_type) {
case DeskBarViewBase::Type::kDeskButton:
bar_type_str = "DeskButtonBar";
break;
case DeskBarViewBase::Type::kOverview:
bar_type_str = "OverviewBar";
break;
}
return base::StringPrintf("%s_%s", result.c_str(), bar_type_str.c_str());
});
INSTANTIATE_TEST_SUITE_P(
All,
DeskButtonTest,
ValuesIn(kDeskButtonTestParamCombinations),
[](const testing::TestParamInfo<DeskButtonTestParams>& info) {
std::stringstream sstream;
sstream << "Shelf" << info.param.alignment;
return sstream.str();
});
}
}