| // Copyright 2014 The Chromium Authors |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #include <memory> |
| #include <string> |
| |
| #include "ash/accessibility/magnifier/fullscreen_magnifier_controller.h" |
| #include "ash/constants/ash_pref_names.h" |
| #include "ash/shell.h" |
| #include "base/command_line.h" |
| #include "base/test/scoped_feature_list.h" |
| #include "build/build_config.h" |
| #include "chrome/browser/ash/accessibility/accessibility_feature_browsertest.h" |
| #include "chrome/browser/ash/accessibility/accessibility_manager.h" |
| #include "chrome/browser/ash/accessibility/accessibility_test_utils.h" |
| #include "chrome/browser/ash/accessibility/automation_test_utils.h" |
| #include "chrome/browser/ash/accessibility/fullscreen_magnifier_test_helper.h" |
| #include "chrome/browser/ash/accessibility/magnification_manager.h" |
| #include "chrome/browser/ui/browser.h" |
| #include "chrome/common/extensions/extension_constants.h" |
| #include "chrome/test/base/in_process_browser_test.h" |
| #include "chrome/test/base/ui_test_utils.h" |
| #include "components/prefs/pref_service.h" |
| #include "content/public/test/accessibility_notification_waiter.h" |
| #include "content/public/test/browser_test.h" |
| #include "extensions/browser/browsertest_util.h" |
| #include "testing/gtest/include/gtest/gtest.h" |
| #include "ui/accessibility/accessibility_features.h" |
| #include "ui/events/event_constants.h" |
| #include "ui/events/keycodes/keyboard_codes_posix.h" |
| #include "ui/events/test/event_generator.h" |
| |
| namespace ash { |
| |
| namespace { |
| |
| const char kDataURIPrefix[] = "data:text/html;charset=utf-8,"; |
| const char kTestHtmlContent[] = |
| "<body style=\"margin-top:0;margin-left:0\">" |
| "<button type=\"button\" name=\"test_button_1\" id=\"test_button\" " |
| "style=\"margin-left:0;margin-top:0;width:100;height:50\">" |
| "Big Button 1</button>" |
| "</body>"; |
| |
| FullscreenMagnifierController* GetFullscreenMagnifierController() { |
| return Shell::Get()->fullscreen_magnifier_controller(); |
| } |
| |
| gfx::Rect GetViewPort() { |
| return GetFullscreenMagnifierController()->GetViewportRect(); |
| } |
| |
| } // namespace |
| |
| class FullscreenMagnifierControllerTest |
| : public AccessibilityFeatureBrowserTest, |
| public ::testing::WithParamInterface<ManifestVersion> { |
| public: |
| FullscreenMagnifierControllerTest() = default; |
| FullscreenMagnifierControllerTest(const FullscreenMagnifierControllerTest&) = |
| delete; |
| FullscreenMagnifierControllerTest& operator=( |
| const FullscreenMagnifierControllerTest&) = delete; |
| ~FullscreenMagnifierControllerTest() override = default; |
| |
| protected: |
| void SetUpCommandLine(base::CommandLine* command_line) override { |
| // Make screens sufficiently wide to host 2 browsers side by side. |
| command_line->AppendSwitchASCII("ash-host-window-bounds", "1200x800"); |
| |
| std::vector<base::test::FeatureRef> enabled_features; |
| std::vector<base::test::FeatureRef> disabled_features; |
| if (GetParam() == ManifestVersion::kTwo) { |
| disabled_features.push_back( |
| ::features::kAccessibilityManifestV3AccessibilityCommon); |
| } else if (GetParam() == ManifestVersion::kThree) { |
| enabled_features.push_back( |
| ::features::kAccessibilityManifestV3AccessibilityCommon); |
| } |
| scoped_feature_list_.InitWithFeatures(enabled_features, disabled_features); |
| AccessibilityFeatureBrowserTest::SetUpCommandLine(command_line); |
| } |
| |
| void SetUpOnMainThread() override { |
| console_observer_ = std::make_unique<ExtensionConsoleErrorObserver>( |
| GetProfile(), extension_misc::kAccessibilityCommonExtensionId); |
| |
| aura::Window* root_window = Shell::Get()->GetPrimaryRootWindow(); |
| generator_ = std::make_unique<ui::test::EventGenerator>(root_window); |
| // Start in a known location, centered on the screen. |
| helper_ = |
| std::make_unique<FullscreenMagnifierTestHelper>(gfx::Point(600, 400)); |
| |
| AccessibilityFeatureBrowserTest::SetUpOnMainThread(); |
| } |
| |
| ui::test::EventGenerator* generator() { return generator_.get(); } |
| FullscreenMagnifierTestHelper* helper() { return helper_.get(); } |
| |
| private: |
| std::unique_ptr<ui::test::EventGenerator> generator_; |
| std::unique_ptr<FullscreenMagnifierTestHelper> helper_; |
| std::unique_ptr<ExtensionConsoleErrorObserver> console_observer_; |
| base::test::ScopedFeatureList scoped_feature_list_; |
| }; |
| |
| INSTANTIATE_TEST_SUITE_P(ManifestV2, |
| FullscreenMagnifierControllerTest, |
| ::testing::Values(ManifestVersion::kTwo)); |
| INSTANTIATE_TEST_SUITE_P(ManifestV3, |
| FullscreenMagnifierControllerTest, |
| ::testing::Values(ManifestVersion::kThree)); |
| |
| IN_PROC_BROWSER_TEST_P(FullscreenMagnifierControllerTest, |
| FollowFocusOnWebButton) { |
| helper()->LoadMagnifier(GetProfile()); |
| |
| AutomationTestUtils utils(extension_misc::kAccessibilityCommonExtensionId); |
| utils.SetUpTestSupport(); |
| const std::string url = std::string(kDataURIPrefix) + kTestHtmlContent; |
| NavigateToUrl(GURL(url)); |
| utils.WaitForPageLoad(url); |
| |
| // Move magnifier window to exclude the button. |
| const gfx::Rect button_bounds = |
| utils.GetNodeBoundsInRoot("Big Button 1", "button"); |
| helper()->MoveMagnifierWindow( |
| button_bounds.right() + GetViewPort().width(), |
| button_bounds.bottom() + GetViewPort().height()); |
| const gfx::Rect view_port_before_focus = GetViewPort(); |
| EXPECT_FALSE(view_port_before_focus.Contains(button_bounds)); |
| |
| // Set the focus on the button. |
| utils.SetFocusOnNode("Big Button 1", "button"); |
| |
| // Verify the magnifier window has moved to contain the button. |
| helper()->WaitForMagnifierBoundsChanged(); |
| EXPECT_TRUE(GetViewPort().Contains(button_bounds)); |
| } |
| |
| IN_PROC_BROWSER_TEST_P(FullscreenMagnifierControllerTest, |
| AnimatesToFollowKeyboardFocus) { |
| helper()->LoadMagnifier(GetProfile()); |
| |
| AutomationTestUtils utils(extension_misc::kAccessibilityCommonExtensionId); |
| utils.SetUpTestSupport(); |
| const std::string url = std::string(kDataURIPrefix) + kTestHtmlContent; |
| NavigateToUrl(GURL(url)); |
| utils.WaitForPageLoad(url); |
| |
| // Move magnifier window to exclude the button. |
| const gfx::Rect button_bounds = |
| utils.GetNodeBoundsInRoot("Big Button 1", "button"); |
| helper()->MoveMagnifierWindow( |
| button_bounds.right() + GetViewPort().width(), |
| button_bounds.bottom() + GetViewPort().height()); |
| const gfx::Rect view_port_before_focus = GetViewPort(); |
| EXPECT_FALSE(view_port_before_focus.Contains(button_bounds)); |
| |
| MagnifierAnimationWaiter magnifier_waiter(GetFullscreenMagnifierController()); |
| |
| // Set the focus on the button. |
| utils.SetFocusOnNode("Big Button 1", "button"); |
| |
| // After the some animation, we should have arrived at the right viewport. |
| do { |
| magnifier_waiter.Wait(); |
| } while (!GetViewPort().Contains(button_bounds)); |
| } |
| |
| IN_PROC_BROWSER_TEST_P(FullscreenMagnifierControllerTest, |
| MovesContinuouslyWithMouse) { |
| GetProfile()->GetPrefs()->SetInteger( |
| prefs::kAccessibilityScreenMagnifierMouseFollowingMode, |
| static_cast<int>(MagnifierMouseFollowingMode::kContinuous)); |
| helper()->LoadMagnifier(GetProfile()); |
| |
| // Screen resolution 1200x800. |
| gfx::Point center_point(600, 400); |
| EXPECT_EQ(GetViewPort().CenterPoint(), center_point); |
| |
| for (int i = 0; i < 3; i++) { |
| // Move left and down. The viewport should move towards the mouse but not |
| // all the way to it. |
| gfx::Point mouse_point = gfx::Point(500 - i * 50, 500 + i * 50); |
| generator()->MoveMouseTo(mouse_point); |
| // No need to wait: Without going through the extension loop needed for |
| // focus observation, the movement is all within the same process. |
| EXPECT_GT(GetViewPort().CenterPoint().x(), mouse_point.x()); |
| EXPECT_LT(GetViewPort().CenterPoint().x(), center_point.x()); |
| EXPECT_LT(GetViewPort().CenterPoint().y(), mouse_point.y()); |
| EXPECT_GT(GetViewPort().CenterPoint().y(), center_point.y()); |
| center_point = GetViewPort().CenterPoint(); |
| } |
| } |
| |
| IN_PROC_BROWSER_TEST_P(FullscreenMagnifierControllerTest, |
| MovesWithMouseAtEdge) { |
| GetProfile()->GetPrefs()->SetInteger( |
| prefs::kAccessibilityScreenMagnifierMouseFollowingMode, |
| static_cast<int>(MagnifierMouseFollowingMode::kEdge)); |
| helper()->LoadMagnifier(GetProfile()); |
| |
| // Screen resolution 1200x800. |
| gfx::Point initial_center = GetViewPort().CenterPoint(); |
| gfx::Point mouse_point(550, 450); |
| generator()->MoveMouseTo(mouse_point); |
| // No need to wait: Without going through the extension loop needed for focus |
| // observation, the movement is all within the same process. |
| EXPECT_EQ(GetViewPort().CenterPoint(), initial_center); |
| |
| // Move left and down. The viewport should not move as we are still within it. |
| gfx::Point new_mouse_point = gfx::Point(500, 500); |
| generator()->MoveMouseTo(new_mouse_point); |
| EXPECT_EQ(GetViewPort().CenterPoint(), initial_center); |
| |
| // Move mouse to the left/bottom edge. The viewport should move in that |
| // direction. Note we have to scale the mouse point based on the magnifer |
| // scale to actually reach the edge of the viewport. |
| new_mouse_point = gfx::Point(0, 800); |
| generator()->MoveMouseTo(new_mouse_point); |
| EXPECT_GT(GetViewPort().CenterPoint().x(), new_mouse_point.x()); |
| EXPECT_LT(GetViewPort().CenterPoint().x(), initial_center.x()); |
| EXPECT_LT(GetViewPort().CenterPoint().y(), new_mouse_point.y()); |
| EXPECT_GT(GetViewPort().CenterPoint().y(), initial_center.y()); |
| } |
| |
| IN_PROC_BROWSER_TEST_P(FullscreenMagnifierControllerTest, |
| ChangeZoomWithAccelerator) { |
| helper()->LoadMagnifier(GetProfile()); |
| |
| // Press keyboard shortcut to zoom in. Default zoom is 2.0. |
| generator()->PressAndReleaseKeyAndModifierKeys( |
| ui::VKEY_BRIGHTNESS_UP, ui::EF_CONTROL_DOWN | ui::EF_ALT_DOWN); |
| float scale = GetFullscreenMagnifierController()->GetScale(); |
| EXPECT_LT(2.0f, scale); |
| |
| // Keyboard shortcut to zoom out. |
| generator()->PressAndReleaseKeyAndModifierKeys( |
| ui::VKEY_BRIGHTNESS_DOWN, ui::EF_CONTROL_DOWN | ui::EF_ALT_DOWN); |
| // Note the scale might not be 2.0 again. |
| EXPECT_GT(scale, GetFullscreenMagnifierController()->GetScale()); |
| } |
| |
| IN_PROC_BROWSER_TEST_P(FullscreenMagnifierControllerTest, ChangeZoomWithPrefs) { |
| helper()->LoadMagnifier(GetProfile()); |
| |
| // Change the bounds pref. |
| GetProfile()->GetPrefs()->SetDouble(prefs::kAccessibilityScreenMagnifierScale, |
| 4.0); |
| EXPECT_EQ(4.0, GetFullscreenMagnifierController()->GetScale()); |
| |
| GetProfile()->GetPrefs()->SetDouble(prefs::kAccessibilityScreenMagnifierScale, |
| 10.5); |
| EXPECT_EQ(10.5, GetFullscreenMagnifierController()->GetScale()); |
| } |
| |
| // TODO(crbug.com/261462562): Add centered mouse following mode browsertest. |
| |
| } // namespace ash |