blob: 7de4c7b97cbc6f8efefb060bf56f1df8f8e775b2 [file] [log] [blame]
// Copyright 2022 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "chrome/browser/ash/arc/input_overlay/ui/menu_entry_view.h"
#include <string>
#include "ash/public/cpp/window_properties.h"
#include "ash/shell.h"
#include "base/test/bind.h"
#include "chrome/browser/ash/arc/input_overlay/constants.h"
#include "chrome/browser/ash/arc/input_overlay/display_overlay_controller.h"
#include "chrome/browser/ash/arc/input_overlay/test/arc_test_window.h"
#include "chrome/browser/ash/arc/input_overlay/touch_injector.h"
#include "chrome/browser/ash/arc/input_overlay/ui/input_menu_view.h"
#include "chrome/browser/ash/arc/input_overlay/util.h"
#include "components/exo/test/exo_test_base.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "ui/events/base_event_utils.h"
#include "ui/events/event.h"
#include "ui/events/types/event_type.h"
#include "ui/gfx/geometry/test/geometry_util.h"
namespace arc::input_overlay {
class MenuEntryViewTest : public exo::test::ExoTestBase {
protected:
MenuEntryViewTest() = default;
~MenuEntryViewTest() override = default;
void PressLeftMouseAtMenuEntryView() {
// Press down at the center of the menu entry view.
menu_entry_view_ = display_overlay_controller_->GetMenuEntryView();
local_location_ = menu_entry_view_->bounds().CenterPoint();
menu_entry_view_->OnMousePressed(
ui::MouseEvent(ui::ET_MOUSE_PRESSED, local_location_, local_location_,
ui::EventTimeForNow(), ui::EF_LEFT_MOUSE_BUTTON,
ui::EF_LEFT_MOUSE_BUTTON));
}
void TouchPressAtMenuEntryView() {
menu_entry_view_ = display_overlay_controller_->GetMenuEntryView();
local_location_ = menu_entry_view_->bounds().CenterPoint();
auto scroll_begin = ui::GestureEvent(
local_location_.x(), local_location_.y(), ui::EF_NONE,
ui::EventTimeForNow(),
ui::GestureEventDetails(ui::ET_GESTURE_SCROLL_BEGIN, 0, 0));
menu_entry_view_->OnGestureEvent(&scroll_begin);
}
void MouseDragMenuEntryViewBy(const gfx::Vector2d& move) {
menu_entry_view_ = display_overlay_controller_->GetMenuEntryView();
local_location_ += move;
menu_entry_view_->OnMouseDragged(
ui::MouseEvent(ui::ET_MOUSE_DRAGGED, local_location_, local_location_,
ui::EventTimeForNow(), ui::EF_LEFT_MOUSE_BUTTON, 0));
}
void TouchMoveAtMenuEntryViewBy(const gfx::Vector2d& move) {
local_location_ += move;
auto scroll_begin =
ui::GestureEvent(local_location_.x(), local_location_.y(), ui::EF_NONE,
ui::EventTimeForNow(),
ui::GestureEventDetails(ui::ET_GESTURE_SCROLL_UPDATE,
move.x(), move.y()));
menu_entry_view_->OnGestureEvent(&scroll_begin);
}
void ReleaseLeftMouseAtMenuEntryView() {
menu_entry_view_ = display_overlay_controller_->GetMenuEntryView();
menu_entry_view_->OnMouseReleased(
ui::MouseEvent(ui::ET_MOUSE_RELEASED, local_location_, local_location_,
ui::EventTimeForNow(), ui::EF_LEFT_MOUSE_BUTTON,
ui::EF_LEFT_MOUSE_BUTTON));
}
void TouchReleaseAtMenuEntryView() {
auto scroll_end =
ui::GestureEvent(local_location_.x(), local_location_.y(), ui::EF_NONE,
ui::EventTimeForNow(),
ui::GestureEventDetails(ui::ET_GESTURE_SCROLL_END));
menu_entry_view_->OnGestureEvent(&scroll_end);
}
void TapAtMenuEntryView() {
auto scroll_end = ui::GestureEvent(
local_location_.x(), local_location_.y(), ui::EF_NONE,
ui::EventTimeForNow(), ui::GestureEventDetails(ui::ET_GESTURE_TAP));
menu_entry_view_->OnGestureEvent(&scroll_end);
}
bool DisplayControllerHasInputMenuView() {
return display_overlay_controller_->HasMenuView();
}
gfx::Rect GetInputMappingViewBounds() {
return display_overlay_controller_->GetInputMappingViewBoundsForTesting();
}
InputMenuView* GetInputMenuFromDisplayController() {
return display_overlay_controller_->GetInputMenuView();
}
void CloseInputMenuView() {
display_overlay_controller_->SetDisplayMode(DisplayMode::kView);
}
void SimulateMinimizeAndRestoreApp() {
display_overlay_controller_.reset();
display_overlay_controller_ =
std::make_unique<DisplayOverlayController>(touch_injector_.get(),
/*first_launch=*/false);
menu_entry_view_ = display_overlay_controller_->GetMenuEntryView();
menu_entry_view_->set_allow_reposition(true);
}
// Kept around to determine bounds(), not owned.
raw_ptr<MenuEntryView> menu_entry_view_;
// Used to simulate mouse actions at a particular location, to be changed upon
// dragging.
gfx::Point local_location_;
private:
void SetUp() override {
exo::test::ExoTestBase::SetUp();
arc_test_window_ = std::make_unique<test::ArcTestWindow>(
exo_test_helper(), ash::Shell::GetPrimaryRootWindow(),
"org.chromium.arc.testapp.inputoverlay");
touch_injector_ = std::make_unique<TouchInjector>(
arc_test_window_->GetWindow(),
*arc_test_window_->GetWindow()->GetProperty(ash::kArcPackageNameKey),
base::BindLambdaForTesting(
[&](std::unique_ptr<AppDataProto>, std::string) {}));
touch_injector_->set_allow_reposition(true);
display_overlay_controller_ = std::make_unique<DisplayOverlayController>(
touch_injector_.get(), /*first_launch=*/false);
menu_entry_view_ = display_overlay_controller_->GetMenuEntryView();
menu_entry_view_->set_allow_reposition(true);
}
void TearDown() override {
menu_entry_view_ = nullptr;
display_overlay_controller_.reset();
touch_injector_.reset();
arc_test_window_.reset();
exo::test::ExoTestBase::TearDown();
}
std::unique_ptr<TouchInjector> touch_injector_;
std::unique_ptr<test::ArcTestWindow> arc_test_window_;
std::unique_ptr<DisplayOverlayController> display_overlay_controller_;
};
TEST_F(MenuEntryViewTest, TestDragMove) {
// Get initial positions.
auto bounds = GetInputMappingViewBounds();
auto initial_pos = menu_entry_view_->origin();
auto move_vector = gfx::Vector2d(5, 5);
// Drag move by mouse.
PressLeftMouseAtMenuEntryView();
MouseDragMenuEntryViewBy(move_vector);
ReleaseLeftMouseAtMenuEntryView();
// Check that input menu view does not open as a result of mouse dragging.
EXPECT_FALSE(DisplayControllerHasInputMenuView());
// Verify that the initial position is within expectation.
EXPECT_EQ(menu_entry_view_->origin(), initial_pos + move_vector);
// Click menu entry view.
PressLeftMouseAtMenuEntryView();
ReleaseLeftMouseAtMenuEntryView();
// Check that resulting input menu view is not offscreen.
auto* input_menu_view = GetInputMenuFromDisplayController();
EXPECT_NE(input_menu_view, nullptr);
EXPECT_LE(input_menu_view->y() + input_menu_view->height(), bounds.height());
// Close the input menu view.
CloseInputMenuView();
// Get initial positions again.
initial_pos = menu_entry_view_->origin();
move_vector = gfx::Vector2d(-5, -5);
// Drag move by touch.
TouchPressAtMenuEntryView();
TouchMoveAtMenuEntryViewBy(move_vector);
TouchReleaseAtMenuEntryView();
// Check that input menu view does not open as a result of touch dragging.
EXPECT_FALSE(DisplayControllerHasInputMenuView());
// Verify that the initial position is within expectation.
EXPECT_EQ(menu_entry_view_->origin(), initial_pos + move_vector);
// Tap menu entry view.
TapAtMenuEntryView();
// Check that input menu view exists as a result of a touch.
EXPECT_TRUE(DisplayControllerHasInputMenuView());
// Check that resulting input menu view is not offscreen.
input_menu_view = GetInputMenuFromDisplayController();
EXPECT_LE(input_menu_view->y() + input_menu_view->height(), bounds.height());
}
TEST_F(MenuEntryViewTest, TestArrowKeyMove) {
// Arrow key left single press & release.
auto updated_pos = menu_entry_view_->origin();
menu_entry_view_->OnKeyPressed(
ui::KeyEvent(ui::ET_KEY_PRESSED, ui::VKEY_LEFT, ui::EF_NONE));
menu_entry_view_->OnKeyReleased(
ui::KeyEvent(ui::ET_KEY_RELEASED, ui::VKEY_LEFT, ui::EF_NONE));
auto move_left = gfx::Vector2d(-kArrowKeyMoveDistance, 0);
updated_pos += move_left;
EXPECT_EQ(updated_pos, menu_entry_view_->origin());
// Arrow key down single press & release.
updated_pos = menu_entry_view_->origin();
menu_entry_view_->OnKeyPressed(
ui::KeyEvent(ui::ET_KEY_PRESSED, ui::VKEY_DOWN, ui::EF_NONE));
menu_entry_view_->OnKeyReleased(
ui::KeyEvent(ui::ET_KEY_RELEASED, ui::VKEY_DOWN, ui::EF_NONE));
auto move_down = gfx::Vector2d(0, kArrowKeyMoveDistance);
updated_pos += move_down;
EXPECT_EQ(updated_pos, menu_entry_view_->origin());
// Arrow key right single press & release.
updated_pos = menu_entry_view_->origin();
int key_press_times = 5;
auto move_right = gfx::Vector2d(kArrowKeyMoveDistance, 0);
for (int i = 0; i < key_press_times; i++) {
menu_entry_view_->OnKeyPressed(
ui::KeyEvent(ui::ET_KEY_PRESSED, ui::VKEY_RIGHT, ui::EF_NONE));
updated_pos += move_right;
}
menu_entry_view_->OnKeyReleased(
ui::KeyEvent(ui::ET_KEY_RELEASED, ui::VKEY_RIGHT, ui::EF_NONE));
EXPECT_EQ(updated_pos, menu_entry_view_->origin());
}
TEST_F(MenuEntryViewTest, TestPersistentPosition) {
// Move menu entry to another location.
auto initial_pos = menu_entry_view_->origin();
auto move_vector = gfx::Vector2d(5, 5);
PressLeftMouseAtMenuEntryView();
MouseDragMenuEntryViewBy(move_vector);
ReleaseLeftMouseAtMenuEntryView();
// Verify that the resulting position is within expectation.
auto expected_pos = initial_pos + move_vector;
EXPECT_EQ(menu_entry_view_->origin(), expected_pos);
// Simulate minimizing and restoring the test application.
SimulateMinimizeAndRestoreApp();
// Check that the position of the menu entry view persisted from the last
// customization.
EXPECT_EQ(menu_entry_view_->origin(), expected_pos);
}
} // namespace arc::input_overlay