OLD | NEW |
| (Empty) |
1 // Copyright 2015 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 "content/browser/renderer_host/input/touch_selection_controller_client_
aura.h" | |
6 | |
7 #include "base/json/json_reader.h" | |
8 #include "base/run_loop.h" | |
9 #include "content/browser/renderer_host/render_widget_host_view_aura.h" | |
10 #include "content/browser/web_contents/web_contents_impl.h" | |
11 #include "content/public/test/browser_test_utils.h" | |
12 #include "content/public/test/content_browser_test.h" | |
13 #include "content/public/test/content_browser_test_utils.h" | |
14 #include "content/shell/browser/shell.h" | |
15 #include "ui/aura/window.h" | |
16 #include "ui/aura/window_tree_host.h" | |
17 #include "ui/events/event_utils.h" | |
18 #include "ui/events/test/event_generator.h" | |
19 #include "ui/touch_selection/touch_selection_controller_test_api.h" | |
20 | |
21 namespace content { | |
22 namespace { | |
23 | |
24 bool JSONToPoint(const std::string& str, gfx::PointF* point) { | |
25 scoped_ptr<base::Value> value = base::JSONReader::Read(str); | |
26 if (!value) | |
27 return false; | |
28 base::DictionaryValue* root; | |
29 if (!value->GetAsDictionary(&root)) | |
30 return false; | |
31 double x, y; | |
32 if (!root->GetDouble("x", &x)) | |
33 return false; | |
34 if (!root->GetDouble("y", &y)) | |
35 return false; | |
36 point->set_x(x); | |
37 point->set_y(y); | |
38 return true; | |
39 } | |
40 | |
41 // A mock touch selection menu runner to use whenever a default one is not | |
42 // installed. | |
43 class TestTouchSelectionMenuRunner : public ui::TouchSelectionMenuRunner { | |
44 public: | |
45 TestTouchSelectionMenuRunner() : menu_opened_(false) {} | |
46 ~TestTouchSelectionMenuRunner() override {} | |
47 | |
48 private: | |
49 void OpenMenu(ui::TouchSelectionMenuClient* client, | |
50 const gfx::Rect& anchor_rect, | |
51 const gfx::Size& handle_image_size, | |
52 aura::Window* context) override { | |
53 menu_opened_ = true; | |
54 } | |
55 | |
56 void CloseMenu() override { menu_opened_ = false; } | |
57 | |
58 bool IsRunning() const override { return menu_opened_; } | |
59 | |
60 bool menu_opened_; | |
61 | |
62 DISALLOW_COPY_AND_ASSIGN(TestTouchSelectionMenuRunner); | |
63 }; | |
64 | |
65 } // namespace | |
66 | |
67 class TestTouchSelectionControllerClientAura | |
68 : public TouchSelectionControllerClientAura { | |
69 public: | |
70 explicit TestTouchSelectionControllerClientAura( | |
71 RenderWidgetHostViewAura* rwhva) | |
72 : TouchSelectionControllerClientAura(rwhva), | |
73 expected_event_(ui::SELECTION_HANDLES_SHOWN) { | |
74 show_quick_menu_immediately_for_test_ = true; | |
75 } | |
76 | |
77 ~TestTouchSelectionControllerClientAura() override {} | |
78 | |
79 void InitWaitForSelectionEvent(ui::SelectionEventType expected_event) { | |
80 DCHECK(!run_loop_); | |
81 expected_event_ = expected_event; | |
82 run_loop_.reset(new base::RunLoop()); | |
83 } | |
84 | |
85 void Wait() { | |
86 DCHECK(run_loop_); | |
87 run_loop_->Run(); | |
88 run_loop_.reset(); | |
89 } | |
90 | |
91 private: | |
92 // TouchSelectionControllerClientAura: | |
93 void OnSelectionEvent(ui::SelectionEventType event) override { | |
94 TouchSelectionControllerClientAura::OnSelectionEvent(event); | |
95 if (run_loop_ && event == expected_event_) | |
96 run_loop_->Quit(); | |
97 } | |
98 | |
99 bool IsCommandIdEnabled(int command_id) const override { | |
100 // Return true so that quick menu has something to show. | |
101 return true; | |
102 } | |
103 | |
104 ui::SelectionEventType expected_event_; | |
105 scoped_ptr<base::RunLoop> run_loop_; | |
106 | |
107 DISALLOW_COPY_AND_ASSIGN(TestTouchSelectionControllerClientAura); | |
108 }; | |
109 | |
110 class TouchSelectionControllerClientAuraTest : public ContentBrowserTest { | |
111 public: | |
112 TouchSelectionControllerClientAuraTest() {} | |
113 ~TouchSelectionControllerClientAuraTest() override {} | |
114 | |
115 protected: | |
116 // Starts the test server and navigates to the given url. Sets a large enough | |
117 // size to the root window. Returns after the navigation to the url is | |
118 // complete. | |
119 void StartTestWithPage(const std::string& url) { | |
120 ASSERT_TRUE(test_server()->Start()); | |
121 GURL test_url(test_server()->GetURL(url)); | |
122 NavigateToURL(shell(), test_url); | |
123 aura::Window* content = shell()->web_contents()->GetContentNativeView(); | |
124 content->GetHost()->SetBounds(gfx::Rect(800, 600)); | |
125 } | |
126 | |
127 bool GetPointInsideText(gfx::PointF* point) { | |
128 std::string str; | |
129 if (ExecuteScriptAndExtractString(shell()->web_contents()->GetMainFrame(), | |
130 "get_point_inside_text()", &str)) { | |
131 return JSONToPoint(str, point); | |
132 } | |
133 return false; | |
134 } | |
135 | |
136 bool GetPointInsideTextfield(gfx::PointF* point) { | |
137 std::string str; | |
138 if (ExecuteScriptAndExtractString(shell()->web_contents()->GetMainFrame(), | |
139 "get_point_inside_textfield()", &str)) { | |
140 return JSONToPoint(str, point); | |
141 } | |
142 return false; | |
143 } | |
144 | |
145 private: | |
146 void SetUpOnMainThread() override { | |
147 ContentBrowserTest::SetUpOnMainThread(); | |
148 if (!ui::TouchSelectionMenuRunner::GetInstance()) | |
149 menu_runner_.reset(new TestTouchSelectionMenuRunner); | |
150 } | |
151 | |
152 void TearDownOnMainThread() override { | |
153 menu_runner_ = nullptr; | |
154 ContentBrowserTest::TearDownOnMainThread(); | |
155 } | |
156 | |
157 scoped_ptr<TestTouchSelectionMenuRunner> menu_runner_; | |
158 | |
159 DISALLOW_COPY_AND_ASSIGN(TouchSelectionControllerClientAuraTest); | |
160 }; | |
161 | |
162 // Tests if long-pressing on a text brings up selection handles and the quick | |
163 // menu properly. | |
164 IN_PROC_BROWSER_TEST_F(TouchSelectionControllerClientAuraTest, BasicSelection) { | |
165 // Set the test page up. | |
166 ASSERT_NO_FATAL_FAILURE(StartTestWithPage("files/touch_selection.html")); | |
167 WebContents* web_contents = | |
168 static_cast<WebContentsImpl*>(shell()->web_contents()); | |
169 RenderWidgetHostViewAura* rwhva = static_cast<RenderWidgetHostViewAura*>( | |
170 web_contents->GetRenderWidgetHostView()); | |
171 TestTouchSelectionControllerClientAura* selection_controller_client = | |
172 new TestTouchSelectionControllerClientAura(rwhva); | |
173 rwhva->SetSelectionControllerClientForTest( | |
174 make_scoped_ptr(selection_controller_client)); | |
175 | |
176 EXPECT_EQ(ui::TouchSelectionController::INACTIVE, | |
177 rwhva->selection_controller()->active_status()); | |
178 EXPECT_FALSE(ui::TouchSelectionMenuRunner::GetInstance()->IsRunning()); | |
179 | |
180 // Long-press on the text and wait for handles to appear. | |
181 selection_controller_client->InitWaitForSelectionEvent( | |
182 ui::SELECTION_HANDLES_SHOWN); | |
183 | |
184 gfx::PointF point; | |
185 ASSERT_TRUE(GetPointInsideText(&point)); | |
186 ui::GestureEvent long_press( | |
187 point.x(), point.y(), 0, ui::EventTimeForNow(), | |
188 ui::GestureEventDetails(ui::ET_GESTURE_LONG_PRESS)); | |
189 rwhva->OnGestureEvent(&long_press); | |
190 | |
191 selection_controller_client->Wait(); | |
192 | |
193 // Check if selection is active and the quick menu is showing. | |
194 EXPECT_EQ(ui::TouchSelectionController::SELECTION_ACTIVE, | |
195 rwhva->selection_controller()->active_status()); | |
196 EXPECT_TRUE(ui::TouchSelectionMenuRunner::GetInstance()->IsRunning()); | |
197 } | |
198 | |
199 // Tests if tapping in a textfield brings up the insertion handle and the quick | |
200 // menu properly. | |
201 IN_PROC_BROWSER_TEST_F(TouchSelectionControllerClientAuraTest, BasicInsertion) { | |
202 // Set the test page up. | |
203 ASSERT_NO_FATAL_FAILURE(StartTestWithPage("files/touch_selection.html")); | |
204 WebContents* web_contents = | |
205 static_cast<WebContentsImpl*>(shell()->web_contents()); | |
206 RenderWidgetHostViewAura* rwhva = static_cast<RenderWidgetHostViewAura*>( | |
207 web_contents->GetRenderWidgetHostView()); | |
208 TestTouchSelectionControllerClientAura* selection_controller_client = | |
209 new TestTouchSelectionControllerClientAura(rwhva); | |
210 rwhva->SetSelectionControllerClientForTest( | |
211 make_scoped_ptr(selection_controller_client)); | |
212 | |
213 EXPECT_EQ(ui::TouchSelectionController::INACTIVE, | |
214 rwhva->selection_controller()->active_status()); | |
215 EXPECT_FALSE(ui::TouchSelectionMenuRunner::GetInstance()->IsRunning()); | |
216 | |
217 // Tap inside the textfield and wait for the insertion handle to appear. | |
218 selection_controller_client->InitWaitForSelectionEvent( | |
219 ui::INSERTION_HANDLE_SHOWN); | |
220 | |
221 gfx::PointF point; | |
222 ASSERT_TRUE(GetPointInsideTextfield(&point)); | |
223 ui::GestureEventDetails tap_details(ui::ET_GESTURE_TAP); | |
224 tap_details.set_tap_count(1); | |
225 ui::GestureEvent tap(point.x(), point.y(), 0, ui::EventTimeForNow(), | |
226 tap_details); | |
227 rwhva->OnGestureEvent(&tap); | |
228 | |
229 selection_controller_client->Wait(); | |
230 | |
231 // Check if insertion is active and the quick menu is showing. | |
232 EXPECT_EQ(ui::TouchSelectionController::INSERTION_ACTIVE, | |
233 rwhva->selection_controller()->active_status()); | |
234 EXPECT_TRUE(ui::TouchSelectionMenuRunner::GetInstance()->IsRunning()); | |
235 } | |
236 | |
237 // Tests if the quick menu is hidden whenever a touch point is active. | |
238 IN_PROC_BROWSER_TEST_F(TouchSelectionControllerClientAuraTest, | |
239 QuickMenuHiddenOnTouch) { | |
240 // Set the test page up. | |
241 ASSERT_NO_FATAL_FAILURE(StartTestWithPage("files/touch_selection.html")); | |
242 WebContents* web_contents = | |
243 static_cast<WebContentsImpl*>(shell()->web_contents()); | |
244 RenderWidgetHostViewAura* rwhva = static_cast<RenderWidgetHostViewAura*>( | |
245 web_contents->GetRenderWidgetHostView()); | |
246 TestTouchSelectionControllerClientAura* selection_controller_client = | |
247 new TestTouchSelectionControllerClientAura(rwhva); | |
248 rwhva->SetSelectionControllerClientForTest( | |
249 make_scoped_ptr(selection_controller_client)); | |
250 | |
251 EXPECT_EQ(ui::TouchSelectionController::INACTIVE, | |
252 rwhva->selection_controller()->active_status()); | |
253 EXPECT_FALSE(ui::TouchSelectionMenuRunner::GetInstance()->IsRunning()); | |
254 | |
255 // Long-press on the text and wait for selection handles to appear. | |
256 selection_controller_client->InitWaitForSelectionEvent( | |
257 ui::SELECTION_HANDLES_SHOWN); | |
258 | |
259 gfx::PointF point; | |
260 ASSERT_TRUE(GetPointInsideText(&point)); | |
261 ui::GestureEvent long_press( | |
262 point.x(), point.y(), 0, ui::EventTimeForNow(), | |
263 ui::GestureEventDetails(ui::ET_GESTURE_LONG_PRESS)); | |
264 rwhva->OnGestureEvent(&long_press); | |
265 | |
266 selection_controller_client->Wait(); | |
267 | |
268 EXPECT_EQ(ui::TouchSelectionController::SELECTION_ACTIVE, | |
269 rwhva->selection_controller()->active_status()); | |
270 EXPECT_TRUE(ui::TouchSelectionMenuRunner::GetInstance()->IsRunning()); | |
271 | |
272 ui::test::EventGenerator generator( | |
273 web_contents->GetContentNativeView()->GetRootWindow(), | |
274 web_contents->GetContentNativeView()); | |
275 | |
276 // Put the first finger down: the quick menu should get hidden. | |
277 generator.PressTouchId(0); | |
278 EXPECT_EQ(ui::TouchSelectionController::SELECTION_ACTIVE, | |
279 rwhva->selection_controller()->active_status()); | |
280 EXPECT_FALSE(ui::TouchSelectionMenuRunner::GetInstance()->IsRunning()); | |
281 | |
282 // Put a second finger down: the quick menu should remain hidden. | |
283 generator.PressTouchId(1); | |
284 EXPECT_EQ(ui::TouchSelectionController::SELECTION_ACTIVE, | |
285 rwhva->selection_controller()->active_status()); | |
286 EXPECT_FALSE(ui::TouchSelectionMenuRunner::GetInstance()->IsRunning()); | |
287 | |
288 // Lift the first finger up: the quick menu should still remain hidden. | |
289 generator.ReleaseTouchId(0); | |
290 EXPECT_EQ(ui::TouchSelectionController::SELECTION_ACTIVE, | |
291 rwhva->selection_controller()->active_status()); | |
292 EXPECT_FALSE(ui::TouchSelectionMenuRunner::GetInstance()->IsRunning()); | |
293 | |
294 // Lift the second finger up: the quick menu should re-appear. | |
295 generator.ReleaseTouchId(1); | |
296 EXPECT_EQ(ui::TouchSelectionController::SELECTION_ACTIVE, | |
297 rwhva->selection_controller()->active_status()); | |
298 EXPECT_TRUE(ui::TouchSelectionMenuRunner::GetInstance()->IsRunning()); | |
299 } | |
300 | |
301 // Tests if the quick menu and touch handles are hidden during an scroll. | |
302 IN_PROC_BROWSER_TEST_F(TouchSelectionControllerClientAuraTest, HiddenOnScroll) { | |
303 // Set the test page up. | |
304 ASSERT_NO_FATAL_FAILURE(StartTestWithPage("files/touch_selection.html")); | |
305 WebContents* web_contents = | |
306 static_cast<WebContentsImpl*>(shell()->web_contents()); | |
307 RenderWidgetHostViewAura* rwhva = static_cast<RenderWidgetHostViewAura*>( | |
308 web_contents->GetRenderWidgetHostView()); | |
309 TestTouchSelectionControllerClientAura* selection_controller_client = | |
310 new TestTouchSelectionControllerClientAura(rwhva); | |
311 rwhva->SetSelectionControllerClientForTest( | |
312 make_scoped_ptr(selection_controller_client)); | |
313 ui::TouchSelectionControllerTestApi selection_controller_test_api( | |
314 rwhva->selection_controller()); | |
315 | |
316 EXPECT_EQ(ui::TouchSelectionController::INACTIVE, | |
317 rwhva->selection_controller()->active_status()); | |
318 EXPECT_FALSE(ui::TouchSelectionMenuRunner::GetInstance()->IsRunning()); | |
319 | |
320 // Long-press on the text and wait for selection handles to appear. | |
321 selection_controller_client->InitWaitForSelectionEvent( | |
322 ui::SELECTION_HANDLES_SHOWN); | |
323 | |
324 gfx::PointF point; | |
325 ASSERT_TRUE(GetPointInsideText(&point)); | |
326 ui::GestureEvent long_press( | |
327 point.x(), point.y(), 0, ui::EventTimeForNow(), | |
328 ui::GestureEventDetails(ui::ET_GESTURE_LONG_PRESS)); | |
329 rwhva->OnGestureEvent(&long_press); | |
330 | |
331 selection_controller_client->Wait(); | |
332 | |
333 EXPECT_EQ(ui::TouchSelectionController::SELECTION_ACTIVE, | |
334 rwhva->selection_controller()->active_status()); | |
335 EXPECT_FALSE(selection_controller_test_api.temporarily_hidden()); | |
336 EXPECT_TRUE(ui::TouchSelectionMenuRunner::GetInstance()->IsRunning()); | |
337 | |
338 // Put a finger down: the quick menu should go away, while touch handles stay | |
339 // there. | |
340 ui::TouchEvent touch_down(ui::ET_TOUCH_PRESSED, gfx::PointF(10, 10), 0, | |
341 ui::EventTimeForNow()); | |
342 rwhva->OnTouchEvent(&touch_down); | |
343 EXPECT_EQ(ui::TouchSelectionController::SELECTION_ACTIVE, | |
344 rwhva->selection_controller()->active_status()); | |
345 EXPECT_FALSE(selection_controller_test_api.temporarily_hidden()); | |
346 EXPECT_FALSE(ui::TouchSelectionMenuRunner::GetInstance()->IsRunning()); | |
347 | |
348 // Start scrolling: touch handles should get hidden, while touch selection is | |
349 // still active. | |
350 ui::GestureEvent scroll_begin( | |
351 10, 10, 0, ui::EventTimeForNow(), | |
352 ui::GestureEventDetails(ui::ET_GESTURE_SCROLL_BEGIN)); | |
353 rwhva->OnGestureEvent(&scroll_begin); | |
354 EXPECT_EQ(ui::TouchSelectionController::SELECTION_ACTIVE, | |
355 rwhva->selection_controller()->active_status()); | |
356 EXPECT_TRUE(selection_controller_test_api.temporarily_hidden()); | |
357 EXPECT_FALSE(ui::TouchSelectionMenuRunner::GetInstance()->IsRunning()); | |
358 | |
359 // End scrolling: touch handles should re-appear. | |
360 ui::GestureEvent scroll_end( | |
361 10, 10, 0, ui::EventTimeForNow(), | |
362 ui::GestureEventDetails(ui::ET_GESTURE_SCROLL_END)); | |
363 rwhva->OnGestureEvent(&scroll_end); | |
364 EXPECT_EQ(ui::TouchSelectionController::SELECTION_ACTIVE, | |
365 rwhva->selection_controller()->active_status()); | |
366 EXPECT_FALSE(selection_controller_test_api.temporarily_hidden()); | |
367 EXPECT_FALSE(ui::TouchSelectionMenuRunner::GetInstance()->IsRunning()); | |
368 | |
369 // Lift the finger up: the quick menu should re-appear. | |
370 ui::TouchEvent touch_up(ui::ET_TOUCH_RELEASED, gfx::PointF(10, 10), 0, | |
371 ui::EventTimeForNow()); | |
372 rwhva->OnTouchEvent(&touch_up); | |
373 EXPECT_EQ(ui::TouchSelectionController::SELECTION_ACTIVE, | |
374 rwhva->selection_controller()->active_status()); | |
375 EXPECT_FALSE(selection_controller_test_api.temporarily_hidden()); | |
376 EXPECT_TRUE(ui::TouchSelectionMenuRunner::GetInstance()->IsRunning()); | |
377 } | |
378 | |
379 // Tests if touch selection gets deactivated after an overscroll completes. | |
380 IN_PROC_BROWSER_TEST_F(TouchSelectionControllerClientAuraTest, | |
381 HiddenAfterOverscroll) { | |
382 // Set the page up. | |
383 ASSERT_NO_FATAL_FAILURE(StartTestWithPage("files/touch_selection.html")); | |
384 WebContents* web_contents = | |
385 static_cast<WebContentsImpl*>(shell()->web_contents()); | |
386 RenderWidgetHostViewAura* rwhva = static_cast<RenderWidgetHostViewAura*>( | |
387 web_contents->GetRenderWidgetHostView()); | |
388 TestTouchSelectionControllerClientAura* selection_controller_client = | |
389 new TestTouchSelectionControllerClientAura(rwhva); | |
390 rwhva->SetSelectionControllerClientForTest( | |
391 make_scoped_ptr(selection_controller_client)); | |
392 | |
393 EXPECT_EQ(ui::TouchSelectionController::INACTIVE, | |
394 rwhva->selection_controller()->active_status()); | |
395 EXPECT_FALSE(ui::TouchSelectionMenuRunner::GetInstance()->IsRunning()); | |
396 | |
397 // Long-press on the text and wait for touch handles to appear. | |
398 selection_controller_client->InitWaitForSelectionEvent( | |
399 ui::SELECTION_HANDLES_SHOWN); | |
400 | |
401 gfx::PointF point; | |
402 ASSERT_TRUE(GetPointInsideText(&point)); | |
403 ui::GestureEvent long_press( | |
404 point.x(), point.y(), 0, ui::EventTimeForNow(), | |
405 ui::GestureEventDetails(ui::ET_GESTURE_LONG_PRESS)); | |
406 rwhva->OnGestureEvent(&long_press); | |
407 | |
408 selection_controller_client->Wait(); | |
409 | |
410 EXPECT_EQ(ui::TouchSelectionController::SELECTION_ACTIVE, | |
411 rwhva->selection_controller()->active_status()); | |
412 EXPECT_TRUE(ui::TouchSelectionMenuRunner::GetInstance()->IsRunning()); | |
413 | |
414 // Scroll such that an overscroll is initiated and wait for it to complete: | |
415 // touch selection should not be active at the end. | |
416 selection_controller_client->InitWaitForSelectionEvent( | |
417 ui::SELECTION_HANDLES_CLEARED); | |
418 | |
419 ui::GestureEvent scroll_begin( | |
420 10, 10, 0, ui::EventTimeForNow(), | |
421 ui::GestureEventDetails(ui::ET_GESTURE_SCROLL_BEGIN)); | |
422 rwhva->OnGestureEvent(&scroll_begin); | |
423 | |
424 ui::GestureEvent scroll_update( | |
425 210, 10, 0, ui::EventTimeForNow(), | |
426 ui::GestureEventDetails(ui::ET_GESTURE_SCROLL_UPDATE, 200, 0)); | |
427 rwhva->OnGestureEvent(&scroll_update); | |
428 | |
429 ui::GestureEvent scroll_end( | |
430 210, 10, 0, ui::EventTimeForNow(), | |
431 ui::GestureEventDetails(ui::ET_GESTURE_SCROLL_END)); | |
432 rwhva->OnGestureEvent(&scroll_end); | |
433 | |
434 selection_controller_client->Wait(); | |
435 | |
436 EXPECT_EQ(ui::TouchSelectionController::INACTIVE, | |
437 rwhva->selection_controller()->active_status()); | |
438 EXPECT_FALSE(ui::TouchSelectionMenuRunner::GetInstance()->IsRunning()); | |
439 } | |
440 | |
441 } // namespace content | |
OLD | NEW |