1 // Copyright 2014 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.
5 #include "ui/chromeos/touch_exploration_controller.h"
7 #include "ash/accessibility_delegate.h"
9 #include "ash/test/ash_test_base.h"
10 #include "base/test/simple_test_tick_clock.h"
11 #include "base/time/time.h"
12 #include "chrome/browser/ui/browser.h"
13 #include "chrome/browser/ui/tabs/tab_strip_model.h"
14 #include "chrome/test/base/in_process_browser_test.h"
15 #include "chrome/test/base/ui_test_utils.h"
16 #include "content/public/test/browser_test_utils.h"
17 #include "ui/aura/client/cursor_client.h"
18 #include "ui/aura/window_tree_host.h"
19 #include "ui/compositor/compositor.h"
20 #include "ui/compositor/test/draw_waiter_for_test.h"
21 #include "ui/events/event.h"
22 #include "ui/events/event_utils.h"
23 #include "ui/events/test/event_generator.h"
24 #include "ui/events/test/test_event_handler.h"
28 class TouchExplorationTest : public InProcessBrowserTest {
30 TouchExplorationTest() : simulated_clock_(new base::SimpleTestTickClock()) {
31 // Tests fail if time is ever 0.
32 simulated_clock_->Advance(base::TimeDelta::FromMilliseconds(10));
34 virtual ~TouchExplorationTest() {}
37 virtual void SetUpOnMainThread() OVERRIDE {
38 // The RenderView for WebContents is created as a result of the
39 // navigation to the New Tab page which is done as part of the test
40 // SetUp. The creation involves sending a resize message to the renderer
41 // process. Here we wait for the resize ack to be received, because
42 // currently WindowEventDispatcher has code to hold touch and mouse
43 // move events until resize is complete (crbug.com/384342) which
44 // interferes with this test.
45 content::WebContents* web_contents =
46 browser()->tab_strip_model()->GetActiveWebContents();
47 content::WaitForResizeComplete(web_contents);
48 root_window_ = ash::Shell::GetInstance()->GetPrimaryRootWindow();
49 event_handler_.reset(new ui::test::TestEventHandler());
50 root_window_->AddPreTargetHandler(event_handler_.get());
53 virtual void TearDownOnMainThread() OVERRIDE {
54 SwitchTouchExplorationMode(false);
55 root_window_->RemovePreTargetHandler(event_handler_.get());
58 void SwitchTouchExplorationMode(bool on) {
59 ash::AccessibilityDelegate* ad =
60 ash::Shell::GetInstance()->accessibility_delegate();
61 if (on != ad->IsSpokenFeedbackEnabled())
62 ad->ToggleSpokenFeedback(ash::A11Y_NOTIFICATION_NONE);
65 base::TimeDelta Now() {
66 return base::TimeDelta::FromInternalValue(
67 simulated_clock_->NowTicks().ToInternalValue());
70 ui::GestureDetector::Config gesture_detector_config_;
71 base::SimpleTestTickClock* simulated_clock_;
72 aura::Window* root_window_;
73 scoped_ptr<ui::test::TestEventHandler> event_handler_;
76 DISALLOW_COPY_AND_ASSIGN(TouchExplorationTest);
79 // This test turns the touch exploration mode off and confirms that events
81 IN_PROC_BROWSER_TEST_F(TouchExplorationTest, NoRewritingEventsWhenOff) {
82 SwitchTouchExplorationMode(false);
83 ui::test::EventGenerator generator(root_window_);
85 base::TimeDelta initial_time = Now();
86 ui::TouchEvent initial_press(
87 ui::ET_TOUCH_PRESSED, gfx::Point(99, 200), 1, initial_time);
88 generator.Dispatch(&initial_press);
90 // Since the touch exploration controller doesn't know if the user is
91 // double-tapping or not, touch exploration is only initiated if the
92 // 300 ms has elapsed and the finger does not move fast enough to begin
93 // gestures. Here, the touch move event is not important as a move, but
94 // a way to create time advancement.
95 ui::TouchEvent touch_time_advance(ui::ET_TOUCH_MOVED,
99 gesture_detector_config_.double_tap_timeout +
100 base::TimeDelta::FromMilliseconds(1));
101 generator.Dispatch(&touch_time_advance);
103 EXPECT_EQ(0, event_handler_->num_mouse_events());
104 EXPECT_EQ(2, event_handler_->num_touch_events());
105 event_handler_->Reset();
107 generator.MoveTouchId(gfx::Point(11, 12), 1);
108 EXPECT_EQ(0, event_handler_->num_mouse_events());
109 EXPECT_EQ(1, event_handler_->num_touch_events());
110 event_handler_->Reset();
112 initial_time = Now();
113 ui::TouchEvent second_initial_press(
114 ui::ET_TOUCH_PRESSED, gfx::Point(499, 600), 2, initial_time);
115 generator.Dispatch(&second_initial_press);
116 ui::TouchEvent second_touch_time_advance(
118 gfx::Point(500, 600),
120 initial_time + gesture_detector_config_.double_tap_timeout +
121 base::TimeDelta::FromMilliseconds(1));
122 generator.Dispatch(&second_touch_time_advance);
123 EXPECT_EQ(0, event_handler_->num_mouse_events());
124 EXPECT_EQ(2, event_handler_->num_touch_events());
127 // This test turns the touch exploration mode on and confirms that events get
129 IN_PROC_BROWSER_TEST_F(TouchExplorationTest, RewritesEventsWhenOn) {
130 SwitchTouchExplorationMode(true);
131 ui::test::EventGenerator generator(root_window_);
133 base::TimeDelta initial_time = Now();
134 ui::TouchEvent initial_press(
135 ui::ET_TOUCH_PRESSED, gfx::Point(100, 200), 1, initial_time);
136 generator.Dispatch(&initial_press);
138 // Since the touch exploration controller doesn't know if the user is
139 // double-tapping or not, touch exploration is only initiated if the
140 // 300 ms has elapsed and the finger does not move fast enough to begin
141 // gestures. Here, the touch move event is not important as a move, but
142 // a way to create time advancement.
143 ui::TouchEvent touch_time_advance(ui::ET_TOUCH_MOVED,
144 gfx::Point(100, 200),
147 gesture_detector_config_.double_tap_timeout +
148 base::TimeDelta::FromMilliseconds(1));
149 generator.Dispatch(&touch_time_advance);
151 // Number of mouse events may be greater than 1 because of ET_MOUSE_ENTERED.
152 EXPECT_GT(event_handler_->num_mouse_events(), 0);
153 EXPECT_EQ(0, event_handler_->num_touch_events());
154 event_handler_->Reset();
156 initial_time = Now();
157 ui::TouchEvent second_initial_press(
158 ui::ET_TOUCH_PRESSED, gfx::Point(500, 600), 2, initial_time);
159 generator.Dispatch(&second_initial_press);
160 ui::TouchEvent second_touch_time_advance(
162 gfx::Point(500, 600),
164 initial_time + gesture_detector_config_.double_tap_timeout +
165 base::TimeDelta::FromMilliseconds(1));
166 generator.Dispatch(&second_touch_time_advance);
167 EXPECT_GT(event_handler_->num_mouse_events(), 0);
168 EXPECT_EQ(1, event_handler_->num_touch_events());
169 event_handler_->Reset();
171 // Stop the pending long press event. In some configurations, shutting down
172 // the browser can take longer than the long press timeout, and a long press
173 // event can come after the browser is already partly shut down, which causes
174 // the test to crash.
175 ui::TouchEvent release_second_touch(
176 ui::ET_TOUCH_RELEASED,
177 gfx::Point(500, 600),
179 initial_time + gesture_detector_config_.double_tap_timeout +
180 base::TimeDelta::FromMilliseconds(1));
181 generator.Dispatch(&release_second_touch);
182 EXPECT_GT(event_handler_->num_mouse_events(), 0);
183 EXPECT_EQ(1, event_handler_->num_touch_events());
186 // This test makes sure that after the user clicks with split tap,
187 // they continue to touch exploration mode if the original touch exploration
188 // finger is still on the screen.
189 IN_PROC_BROWSER_TEST_F(TouchExplorationTest, SplitTapExplore) {
190 SwitchTouchExplorationMode(true);
191 ui::test::EventGenerator generator(root_window_);
192 aura::client::CursorClient* cursor_client =
193 aura::client::GetCursorClient(root_window_);
195 // Mouse events should show the cursor.
196 generator.MoveMouseTo(gfx::Point(30, 31));
197 EXPECT_TRUE(cursor_client->IsMouseEventsEnabled());
198 EXPECT_TRUE(cursor_client->IsCursorVisible());
200 // The cursor should be shown immediately after the press, and hidden
202 base::TimeDelta initial_time = Now();
203 ui::TouchEvent initial_press(
204 ui::ET_TOUCH_PRESSED, gfx::Point(100, 200), 1, initial_time);
205 generator.Dispatch(&initial_press);
206 EXPECT_TRUE(cursor_client->IsMouseEventsEnabled());
207 EXPECT_TRUE(cursor_client->IsCursorVisible());
209 // Initiate touch explore by waiting for the tap timer timeout. Time is
210 // advanced by sending a move event after the timeout period.
211 ui::TouchEvent touch_time_advance(
213 gfx::Point(100, 200),
215 initial_time + gesture_detector_config_.double_tap_timeout +
216 base::TimeDelta::FromMilliseconds(1));
217 generator.Dispatch(&touch_time_advance);
218 EXPECT_TRUE(cursor_client->IsMouseEventsEnabled());
219 EXPECT_FALSE(cursor_client->IsCursorVisible());
220 event_handler_->Reset();
222 // Press and release with a second finger for split tap. This should send
223 // touch press and release events which should send a click press and release.
224 // Once the press is passed through, mouse events should be disabled.
225 // Mouse events are reenabled after the release.
226 generator.set_current_location(gfx::Point(102, 202));
227 generator.PressTouchId(2);
228 EXPECT_FALSE(cursor_client->IsMouseEventsEnabled());
229 EXPECT_FALSE(cursor_client->IsCursorVisible());
230 generator.ReleaseTouchId(2);
231 EXPECT_TRUE(cursor_client->IsMouseEventsEnabled());
232 EXPECT_FALSE(cursor_client->IsCursorVisible());
233 EXPECT_EQ(2, event_handler_->num_touch_events());
234 event_handler_->Reset();
236 // Continuing to move the touch exploration finger should send more mouse
238 generator.MoveTouchId(gfx::Point(509, 609), 1);
239 EXPECT_EQ(0, event_handler_->num_touch_events());
240 EXPECT_TRUE(cursor_client->IsMouseEventsEnabled());
241 EXPECT_FALSE(cursor_client->IsCursorVisible());