| // Copyright 2021 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 "content/browser/accessibility/touch_passthrough_manager.h" |
| |
| #include <string> |
| #include <vector> |
| |
| #include "base/strings/stringprintf.h" |
| #include "content/browser/accessibility/browser_accessibility.h" |
| #include "content/browser/accessibility/browser_accessibility_manager.h" |
| #include "testing/gmock/include/gmock/gmock.h" |
| #include "testing/gtest/include/gtest/gtest.h" |
| #include "ui/accessibility/ax_node_data.h" |
| #include "ui/accessibility/ax_tree_update.h" |
| |
| using ::testing::ContainerEq; |
| |
| namespace content { |
| |
| // Subclass of TouchPassthroughManager enabling us to unit-test it. |
| class TestTouchPassthroughManager : public TouchPassthroughManager { |
| public: |
| TestTouchPassthroughManager() : TouchPassthroughManager(nullptr) { |
| ui::AXNodeData root; |
| root.id = 1; |
| root.child_ids = {2, 3}; |
| root.relative_bounds.bounds = gfx::RectF(0, 0, 800, 600); |
| |
| ui::AXNodeData target1; |
| target1.id = 2; |
| target1.AddBoolAttribute(ax::mojom::BoolAttribute::kTouchPassthrough, true); |
| target1.relative_bounds.bounds = gfx::RectF(100, 100, 400, 100); |
| |
| ui::AXNodeData target2; |
| target2.id = 3; |
| target2.AddBoolAttribute(ax::mojom::BoolAttribute::kTouchPassthrough, true); |
| target2.relative_bounds.bounds = gfx::RectF(100, 200, 400, 100); |
| |
| browser_accessibility_manager_.reset(BrowserAccessibilityManager::Create( |
| MakeAXTreeUpdate(root, target1, target2), nullptr)); |
| } |
| |
| ~TestTouchPassthroughManager() override = default; |
| |
| const std::vector<std::string> event_log() { return event_log_; } |
| |
| private: |
| std::unique_ptr<BrowserAccessibilityManager> browser_accessibility_manager_; |
| std::vector<std::string> event_log_; |
| base::TimeTicks previous_time_; |
| bool button_down_ = false; |
| |
| void SendHitTest( |
| const gfx::Point& point_in_frame_pixels, |
| base::OnceCallback<void(BrowserAccessibilityManager* hit_manager, |
| int hit_node_id)> callback) override { |
| BrowserAccessibility* result = |
| browser_accessibility_manager_->GetRoot()->ApproximateHitTest( |
| point_in_frame_pixels); |
| int hit_node_id = result ? result->GetId() : 0; |
| std::move(callback).Run(browser_accessibility_manager_.get(), hit_node_id); |
| } |
| |
| void CancelTouchesAndDestroyTouchDriver() override {} |
| |
| void SimulatePress(const gfx::Point& point, |
| const base::TimeTicks& time) override { |
| EXPECT_FALSE(button_down_); |
| EXPECT_GE(time, previous_time_); |
| previous_time_ = time; |
| button_down_ = true; |
| event_log_.push_back( |
| base::StringPrintf("Press %d, %d", point.x(), point.y())); |
| } |
| |
| void SimulateMove(const gfx::Point& point, |
| const base::TimeTicks& time) override { |
| EXPECT_TRUE(button_down_); |
| EXPECT_GE(time, previous_time_); |
| previous_time_ = time; |
| event_log_.push_back( |
| base::StringPrintf("Move %d, %d", point.x(), point.y())); |
| } |
| |
| void SimulateCancel(const base::TimeTicks& time) override { |
| EXPECT_TRUE(button_down_); |
| EXPECT_GE(time, previous_time_); |
| previous_time_ = time; |
| button_down_ = false; |
| event_log_.push_back("Cancel"); |
| } |
| |
| void SimulateRelease(const base::TimeTicks& time) override { |
| EXPECT_TRUE(button_down_); |
| EXPECT_GE(time, previous_time_); |
| previous_time_ = time; |
| button_down_ = false; |
| event_log_.push_back("Release"); |
| } |
| }; |
| |
| class TouchPassthroughManagerTest : public testing::Test { |
| public: |
| TouchPassthroughManagerTest() = default; |
| ~TouchPassthroughManagerTest() override = default; |
| |
| protected: |
| private: |
| void SetUp() override {} |
| |
| DISALLOW_COPY_AND_ASSIGN(TouchPassthroughManagerTest); |
| }; |
| |
| TEST_F(TouchPassthroughManagerTest, TapOutsidePassthroughRegion) { |
| TestTouchPassthroughManager manager; |
| manager.OnTouchStart(gfx::Point(5, 5)); |
| manager.OnTouchEnd(); |
| EXPECT_THAT(manager.event_log(), ContainerEq(std::vector<std::string>())); |
| } |
| |
| TEST_F(TouchPassthroughManagerTest, TapInPassthroughRegion) { |
| TestTouchPassthroughManager manager; |
| manager.OnTouchStart(gfx::Point(105, 105)); |
| manager.OnTouchEnd(); |
| EXPECT_THAT(manager.event_log(), ContainerEq(std::vector<std::string>{ |
| "Press 105, 105", "Release"})); |
| } |
| |
| TEST_F(TouchPassthroughManagerTest, DragWithinPassthroughRegion) { |
| TestTouchPassthroughManager manager; |
| manager.OnTouchStart(gfx::Point(105, 105)); |
| manager.OnTouchMove(gfx::Point(495, 195)); |
| manager.OnTouchEnd(); |
| EXPECT_THAT(manager.event_log(), |
| ContainerEq(std::vector<std::string>{ |
| "Press 105, 105", "Move 495, 195", "Release"})); |
| } |
| |
| TEST_F(TouchPassthroughManagerTest, DragOutOfPassthroughRegion) { |
| TestTouchPassthroughManager manager; |
| manager.OnTouchStart(gfx::Point(105, 105)); |
| manager.OnTouchMove(gfx::Point(105, 95)); |
| manager.OnTouchEnd(); |
| EXPECT_THAT(manager.event_log(), ContainerEq(std::vector<std::string>{ |
| "Press 105, 105", "Cancel"})); |
| } |
| |
| TEST_F(TouchPassthroughManagerTest, DragIntoPassthroughRegion) { |
| TestTouchPassthroughManager manager; |
| manager.OnTouchStart(gfx::Point(80, 80)); |
| manager.OnTouchMove(gfx::Point(90, 90)); |
| manager.OnTouchMove(gfx::Point(110, 110)); |
| manager.OnTouchMove(gfx::Point(120, 120)); |
| manager.OnTouchEnd(); |
| EXPECT_THAT(manager.event_log(), |
| ContainerEq(std::vector<std::string>{ |
| "Press 110, 110", "Move 120, 120", "Release"})); |
| } |
| |
| TEST_F(TouchPassthroughManagerTest, DragBetweenPassthroughRegions) { |
| TestTouchPassthroughManager manager; |
| manager.OnTouchStart(gfx::Point(110, 180)); |
| manager.OnTouchMove(gfx::Point(110, 190)); |
| manager.OnTouchMove(gfx::Point(110, 210)); |
| manager.OnTouchMove(gfx::Point(110, 220)); |
| manager.OnTouchEnd(); |
| EXPECT_THAT(manager.event_log(), |
| ContainerEq(std::vector<std::string>{ |
| "Press 110, 180", "Move 110, 190", "Cancel", "Press 110, 210", |
| "Move 110, 220", "Release"})); |
| } |
| |
| } // namespace content |