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