1 // Copyright 2017 The Chromium Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style license that can be 3 // found in the LICENSE file. 4 5 #include "base/run_loop.h" 6 #include "base/win/windows_version.h" 7 #include "build/build_config.h" 8 #include "chrome/browser/ui/views/test/view_event_test_base.h" 9 #include "chrome/test/base/testing_profile.h" 10 #include "ui/aura/env.h" 11 #include "ui/aura/test/env_test_helper.h" 12 #include "ui/aura/window.h" 13 #include "ui/aura/window_tree_host.h" 14 #include "ui/base/models/simple_menu_model.h" 15 #include "ui/base/test/ui_controls.h" 16 #include "ui/events/gestures/gesture_recognizer_impl.h" 17 #include "ui/views/controls/menu/menu_runner.h" 18 19 namespace { 20 21 class TouchEventHandler : public ui::EventHandler { 22 public: TouchEventHandler()23 TouchEventHandler() 24 : call_depth_(0), 25 max_call_depth_(0), 26 num_touch_presses_(0), 27 num_pointers_down_(0), 28 recursion_enabled_(false) {} 29 ~TouchEventHandler()30 ~TouchEventHandler() override {} 31 32 // OnTouchEvent will simulate a second touch event (at |touch_point|) to force 33 // recursion in event handling. ForceRecursionInEventHandler(const gfx::Point & touch_point)34 void ForceRecursionInEventHandler(const gfx::Point& touch_point) { 35 recursion_enabled_ = true; 36 touch_point_ = touch_point; 37 } 38 WaitForIdle()39 void WaitForIdle() { 40 base::RunLoop run_loop(base::RunLoop::Type::kNestableTasksAllowed); 41 run_loop.RunUntilIdle(); 42 } WaitForEvents()43 void WaitForEvents() { 44 base::RunLoop run_loop(base::RunLoop::Type::kNestableTasksAllowed); 45 quit_closure_ = run_loop.QuitClosure(); 46 run_loop.Run(); 47 } 48 max_call_depth() const49 int max_call_depth() const { return max_call_depth_; } 50 num_touch_presses() const51 int num_touch_presses() const { return num_touch_presses_; } 52 num_pointers_down() const53 int num_pointers_down() const { return num_pointers_down_; } 54 set_touch_point(const gfx::Point & pt)55 void set_touch_point(const gfx::Point& pt) { touch_point_ = pt; } 56 57 private: 58 // ui::EventHandler: OnTouchEvent(ui::TouchEvent * event)59 void OnTouchEvent(ui::TouchEvent* event) override { 60 max_call_depth_ = std::max(++call_depth_, max_call_depth_); 61 62 if (recursion_enabled_ && (event->type() == ui::ET_TOUCH_RELEASED)) { 63 recursion_enabled_ = false; 64 ui_controls::SendTouchEvents(ui_controls::PRESS | ui_controls::PRESS, 1, 65 touch_point_.x(), touch_point_.y()); 66 WaitForIdle(); 67 } 68 69 switch (event->type()) { 70 case ui::ET_TOUCH_PRESSED: 71 num_touch_presses_++; 72 num_pointers_down_++; 73 break; 74 case ui::ET_TOUCH_RELEASED: 75 num_pointers_down_--; 76 if (!quit_closure_.is_null() && num_pointers_down_ == 0) { 77 quit_closure_.Run(); 78 } 79 break; 80 default: 81 break; 82 } 83 --call_depth_; 84 } 85 86 int call_depth_; 87 int max_call_depth_; 88 int num_touch_presses_; 89 int num_pointers_down_; 90 base::Closure quit_closure_; 91 bool recursion_enabled_; 92 gfx::Point touch_point_; 93 DISALLOW_COPY_AND_ASSIGN(TouchEventHandler); 94 }; 95 96 class TestingGestureRecognizer : public ui::GestureRecognizerImpl { 97 public: 98 TestingGestureRecognizer() = default; 99 ~TestingGestureRecognizer() override = default; 100 num_touch_press_events() const101 int num_touch_press_events() const { return num_touch_press_events_; } num_touch_release_events() const102 int num_touch_release_events() const { return num_touch_release_events_; } 103 104 protected: 105 // Overriden from GestureRecognizerImpl: ProcessTouchEventPreDispatch(ui::TouchEvent * event,ui::GestureConsumer * consumer)106 bool ProcessTouchEventPreDispatch(ui::TouchEvent* event, 107 ui::GestureConsumer* consumer) override { 108 switch (event->type()) { 109 case ui::ET_TOUCH_PRESSED: 110 num_touch_press_events_++; 111 break; 112 case ui::ET_TOUCH_RELEASED: 113 num_touch_release_events_++; 114 break; 115 default: 116 break; 117 } 118 119 return ui::GestureRecognizerImpl::ProcessTouchEventPreDispatch(event, 120 consumer); 121 } 122 123 private: 124 int num_touch_press_events_ = 0; 125 int num_touch_release_events_ = 0; 126 DISALLOW_COPY_AND_ASSIGN(TestingGestureRecognizer); 127 }; 128 129 } // namespace 130 131 class TouchEventsViewTest : public ViewEventTestBase { 132 public: 133 TouchEventsViewTest() = default; 134 135 // ViewEventTestBase: SetUp()136 void SetUp() override { 137 ViewEventTestBase::SetUp(); 138 139 auto gesture_recognizer = std::make_unique<TestingGestureRecognizer>(); 140 gesture_recognizer_ = gesture_recognizer.get(); 141 aura::test::EnvTestHelper().SetGestureRecognizer( 142 std::move(gesture_recognizer)); 143 } 144 CreateContentsView()145 std::unique_ptr<views::View> CreateContentsView() override { 146 auto touch_view = std::make_unique<views::View>(); 147 touch_view_ = touch_view.get(); 148 return touch_view; 149 } 150 GetPreferredSizeForContents() const151 gfx::Size GetPreferredSizeForContents() const override { 152 return gfx::Size(600, 600); 153 } 154 DoTestOnMessageLoop()155 void DoTestOnMessageLoop() override { 156 // ui_controls::SendTouchEvents which uses InjectTouchInput API only works 157 // on Windows 8 and up. 158 if (base::win::GetVersion() <= base::win::Version::WIN7) { 159 Done(); 160 return; 161 } 162 163 const int touch_pointer_count = 3; 164 TouchEventHandler touch_event_handler; 165 window()->GetNativeWindow()->GetHost()->window()->AddPreTargetHandler( 166 &touch_event_handler); 167 gfx::Point in_content(touch_view_->width() / 2, touch_view_->height() / 2); 168 views::View::ConvertPointToScreen(touch_view_, &in_content); 169 170 ASSERT_TRUE(ui_controls::SendTouchEvents(ui_controls::PRESS, 171 touch_pointer_count, 172 in_content.x(), in_content.y())); 173 touch_event_handler.WaitForIdle(); 174 touch_event_handler.WaitForEvents(); 175 EXPECT_EQ(touch_pointer_count, touch_event_handler.num_touch_presses()); 176 EXPECT_EQ(0, touch_event_handler.num_pointers_down()); 177 178 EXPECT_EQ(touch_pointer_count, 179 gesture_recognizer_->num_touch_press_events()); 180 EXPECT_EQ(touch_pointer_count, 181 gesture_recognizer_->num_touch_release_events()); 182 183 window()->GetNativeWindow()->GetHost()->window()->RemovePreTargetHandler( 184 &touch_event_handler); 185 Done(); 186 } 187 188 protected: 189 views::View* touch_view_ = nullptr; 190 TestingGestureRecognizer* gesture_recognizer_ = nullptr; 191 ui::GestureRecognizer* initial_gr_ = nullptr; 192 193 DISALLOW_COPY_AND_ASSIGN(TouchEventsViewTest); 194 }; 195 196 #if defined(OS_WIN) // Fails on latest versions of Windows. 197 // https://crbug.com/1108551. 198 #define MAYBE_CheckWindowsNativeMessageForTouchEvents \ 199 DISABLED_CheckWindowsNativeMessageForTouchEvents 200 #else 201 #define MAYBE_CheckWindowsNativeMessageForTouchEvents \ 202 CheckWindowsNativeMessageForTouchEvents 203 #endif 204 VIEW_TEST(TouchEventsViewTest, MAYBE_CheckWindowsNativeMessageForTouchEvents) 205 206 class TouchEventsRecursiveViewTest : public TouchEventsViewTest { 207 public: TouchEventsRecursiveViewTest()208 TouchEventsRecursiveViewTest() {} 209 DoTestOnMessageLoop()210 void DoTestOnMessageLoop() override { 211 // ui_controls::SendTouchEvents which uses InjectTouchInput API only works 212 // on Windows 8 and up. 213 if (base::win::GetVersion() <= base::win::Version::WIN7) { 214 Done(); 215 return; 216 } 217 218 const int touch_pointer_count = 1; 219 TouchEventHandler touch_event_handler; 220 window()->GetNativeWindow()->GetHost()->window()->AddPreTargetHandler( 221 &touch_event_handler); 222 gfx::Point in_content(touch_view_->width() / 2, touch_view_->height() / 2); 223 views::View::ConvertPointToScreen(touch_view_, &in_content); 224 touch_event_handler.ForceRecursionInEventHandler(in_content); 225 226 ASSERT_TRUE(ui_controls::SendTouchEvents(ui_controls::PRESS, 227 touch_pointer_count, 228 in_content.x(), in_content.y())); 229 touch_event_handler.WaitForEvents(); 230 231 EXPECT_EQ(touch_pointer_count + 1, touch_event_handler.num_touch_presses()); 232 EXPECT_EQ(0, touch_event_handler.num_pointers_down()); 233 EXPECT_EQ(2, touch_event_handler.max_call_depth()); 234 window()->GetNativeWindow()->GetHost()->window()->RemovePreTargetHandler( 235 &touch_event_handler); 236 Done(); 237 } 238 239 private: 240 DISALLOW_COPY_AND_ASSIGN(TouchEventsRecursiveViewTest); 241 }; 242 243 #if defined(OS_WIN) // Fails on latest versions of Windows. 244 // https://crbug.com/1108551. 245 #define MAYBE_CheckWindowsRecursiveHandler DISABLED_CheckWindowsRecursiveHandler 246 #else 247 #define MAYBE_CheckWindowsRecursiveHandler CheckWindowsRecursiveHandler 248 #endif 249 VIEW_TEST(TouchEventsRecursiveViewTest, MAYBE_CheckWindowsRecursiveHandler) 250