blob: d2aab945ed03c657f254553b8848166b9042602d [file] [log] [blame]
// Copyright 2019 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "ash/system/accessibility/autoclick_menu_bubble_controller.h"
#include "ash/accessibility/accessibility_controller.h"
#include "ash/autoclick/autoclick_controller.h"
#include "ash/shell.h"
#include "ash/test/ash_test_base.h"
#include "base/command_line.h"
#include "ui/accessibility/accessibility_switches.h"
namespace ash {
namespace {
// A buffer for checking whether the menu view is near this region of the
// screen. This buffer allows for things like padding and the shelf size,
// but is still smaller than half the screen size, so that we can check the
// general corner in which the menu is displayed.
const int kMenuViewBoundsBuffer = 100;
ui::GestureEvent CreateTapEvent() {
return ui::GestureEvent(0, 0, 0, base::TimeTicks(),
ui::GestureEventDetails(ui::ET_GESTURE_TAP));
}
} // namespace
class AutoclickMenuBubbleControllerTest : public AshTestBase {
public:
AutoclickMenuBubbleControllerTest() = default;
~AutoclickMenuBubbleControllerTest() override = default;
// testing::Test:
void SetUp() override {
base::CommandLine::ForCurrentProcess()->AppendSwitch(
switches::kEnableExperimentalAccessibilityAutoclick);
AshTestBase::SetUp();
Shell::Get()->accessibility_controller()->SetAutoclickEnabled(true);
}
AutoclickMenuBubbleController* GetBubbleController() {
return Shell::Get()
->autoclick_controller()
->GetMenuBubbleControllerForTesting();
}
AutoclickMenuView* GetMenuView() {
return GetBubbleController() ? GetBubbleController()->menu_view_ : nullptr;
}
views::View* GetMenuButton(AutoclickMenuView::ButtonId view_id) {
AutoclickMenuView* menu_view = GetMenuView();
if (!menu_view)
return nullptr;
return menu_view->GetViewByID(static_cast<int>(view_id));
}
gfx::Rect GetMenuViewBounds() {
return GetBubbleController()
? GetBubbleController()->menu_view_->GetBoundsInScreen()
: gfx::Rect(-kMenuViewBoundsBuffer, -kMenuViewBoundsBuffer);
}
private:
DISALLOW_COPY_AND_ASSIGN(AutoclickMenuBubbleControllerTest);
};
TEST_F(AutoclickMenuBubbleControllerTest, ExistsOnlyWhenAutoclickIsRunning) {
// Cycle a few times to ensure there are no crashes when toggling the feature.
for (int i = 0; i < 2; i++) {
EXPECT_TRUE(GetBubbleController());
EXPECT_TRUE(GetMenuView());
Shell::Get()->accessibility_controller()->SetAutoclickEnabled(false);
EXPECT_FALSE(GetBubbleController());
Shell::Get()->accessibility_controller()->SetAutoclickEnabled(true);
}
}
TEST_F(AutoclickMenuBubbleControllerTest, CanSelectAutoclickTypeFromBubble) {
AccessibilityController* controller =
Shell::Get()->accessibility_controller();
// Set to a different event type than the first event in kTestCases.
controller->SetAutoclickEventType(mojom::AutoclickEventType::kRightClick);
const struct {
AutoclickMenuView::ButtonId view_id;
mojom::AutoclickEventType expected_event_type;
} kTestCases[] = {
{AutoclickMenuView::ButtonId::kLeftClick,
mojom::AutoclickEventType::kLeftClick},
{AutoclickMenuView::ButtonId::kRightClick,
mojom::AutoclickEventType::kRightClick},
{AutoclickMenuView::ButtonId::kDoubleClick,
mojom::AutoclickEventType::kDoubleClick},
{AutoclickMenuView::ButtonId::kDragAndDrop,
mojom::AutoclickEventType::kDragAndDrop},
{AutoclickMenuView::ButtonId::kPause,
mojom::AutoclickEventType::kNoAction},
};
for (const auto& test : kTestCases) {
// Find the autoclick action button for this test case.
views::View* button = GetMenuButton(test.view_id);
ASSERT_TRUE(button) << "No view for id " << static_cast<int>(test.view_id);
// Tap the action button.
ui::GestureEvent event = CreateTapEvent();
button->OnGestureEvent(&event);
// Pref change happened.
EXPECT_EQ(test.expected_event_type, controller->GetAutoclickEventType());
}
}
TEST_F(AutoclickMenuBubbleControllerTest, UnpausesWhenPauseAlreadySelected) {
AccessibilityController* controller =
Shell::Get()->accessibility_controller();
views::View* pause_button =
GetMenuButton(AutoclickMenuView::ButtonId::kPause);
ui::GestureEvent event = CreateTapEvent();
const struct {
mojom::AutoclickEventType event_type;
} kTestCases[]{
{mojom::AutoclickEventType::kRightClick},
{mojom::AutoclickEventType::kLeftClick},
{mojom::AutoclickEventType::kDoubleClick},
{mojom::AutoclickEventType::kDragAndDrop},
};
for (const auto& test : kTestCases) {
controller->SetAutoclickEventType(test.event_type);
// First tap pauses
pause_button->OnGestureEvent(&event);
EXPECT_EQ(mojom::AutoclickEventType::kNoAction,
controller->GetAutoclickEventType());
// Second tap unpauses and reverts to previous state.
pause_button->OnGestureEvent(&event);
EXPECT_EQ(test.event_type, controller->GetAutoclickEventType());
}
}
TEST_F(AutoclickMenuBubbleControllerTest, CanChangePosition) {
AccessibilityController* controller =
Shell::Get()->accessibility_controller();
// Set to a known position for than the first event in kTestCases.
controller->SetAutoclickMenuPosition(mojom::AutoclickMenuPosition::kTopRight);
// Get the full root window bounds to test the position.
gfx::Rect window_bounds = Shell::GetPrimaryRootWindow()->bounds();
// Test cases rotate clockwise.
const struct {
gfx::Point expected_location;
mojom::AutoclickMenuPosition expected_position;
} kTestCases[] = {
{gfx::Point(window_bounds.width(), window_bounds.height()),
mojom::AutoclickMenuPosition::kBottomRight},
{gfx::Point(0, window_bounds.height()),
mojom::AutoclickMenuPosition::kBottomLeft},
{gfx::Point(0, 0), mojom::AutoclickMenuPosition::kTopLeft},
{gfx::Point(window_bounds.width(), 0),
mojom::AutoclickMenuPosition::kTopRight},
};
// Find the autoclick menu position button.
views::View* button = GetMenuButton(AutoclickMenuView::ButtonId::kPosition);
ASSERT_TRUE(button) << "No position button found.";
// Loop through all positions twice.
for (int i = 0; i < 2; i++) {
for (const auto& test : kTestCases) {
// Tap the position button.
ui::GestureEvent event = CreateTapEvent();
button->OnGestureEvent(&event);
// Pref change happened.
EXPECT_EQ(test.expected_position, controller->GetAutoclickMenuPosition());
// Menu is in generally the correct screen location.
EXPECT_LT(
GetMenuViewBounds().ManhattanDistanceToPoint(test.expected_location),
kMenuViewBoundsBuffer);
}
}
}
} // namespace ash