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.
5 #include "content/browser/renderer_host/input/touch_selection_controller_client_aura.h"
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"
24 bool JSONToPoint(const std::string
& str
, gfx::PointF
* point
) {
25 scoped_ptr
<base::Value
> value
= base::JSONReader::Read(str
);
28 base::DictionaryValue
* root
;
29 if (!value
->GetAsDictionary(&root
))
32 if (!root
->GetDouble("x", &x
))
34 if (!root
->GetDouble("y", &y
))
41 // A mock touch selection menu runner to use whenever a default one is not
43 class TestTouchSelectionMenuRunner
: public ui::TouchSelectionMenuRunner
{
45 TestTouchSelectionMenuRunner() : menu_opened_(false) {}
46 ~TestTouchSelectionMenuRunner() override
{}
49 void OpenMenu(ui::TouchSelectionMenuClient
* client
,
50 const gfx::Rect
& anchor_rect
,
51 const gfx::Size
& handle_image_size
,
52 aura::Window
* context
) override
{
56 void CloseMenu() override
{ menu_opened_
= false; }
58 bool IsRunning() const override
{ return menu_opened_
; }
62 DISALLOW_COPY_AND_ASSIGN(TestTouchSelectionMenuRunner
);
67 class TestTouchSelectionControllerClientAura
68 : public TouchSelectionControllerClientAura
{
70 explicit TestTouchSelectionControllerClientAura(
71 RenderWidgetHostViewAura
* rwhva
)
72 : TouchSelectionControllerClientAura(rwhva
),
73 expected_event_(ui::SELECTION_HANDLES_SHOWN
) {
74 show_quick_menu_immediately_for_test_
= true;
77 ~TestTouchSelectionControllerClientAura() override
{}
79 void InitWaitForSelectionEvent(ui::SelectionEventType expected_event
) {
81 expected_event_
= expected_event
;
82 run_loop_
.reset(new base::RunLoop());
92 // TouchSelectionControllerClientAura:
93 void OnSelectionEvent(ui::SelectionEventType event
) override
{
94 TouchSelectionControllerClientAura::OnSelectionEvent(event
);
95 if (run_loop_
&& event
== expected_event_
)
99 bool IsCommandIdEnabled(int command_id
) const override
{
100 // Return true so that quick menu has something to show.
104 ui::SelectionEventType expected_event_
;
105 scoped_ptr
<base::RunLoop
> run_loop_
;
107 DISALLOW_COPY_AND_ASSIGN(TestTouchSelectionControllerClientAura
);
110 class TouchSelectionControllerClientAuraTest
: public ContentBrowserTest
{
112 TouchSelectionControllerClientAuraTest() {}
113 ~TouchSelectionControllerClientAuraTest() override
{}
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
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));
127 bool GetPointInsideText(gfx::PointF
* point
) {
129 if (ExecuteScriptAndExtractString(shell()->web_contents()->GetMainFrame(),
130 "get_point_inside_text()", &str
)) {
131 return JSONToPoint(str
, point
);
136 bool GetPointInsideTextfield(gfx::PointF
* point
) {
138 if (ExecuteScriptAndExtractString(shell()->web_contents()->GetMainFrame(),
139 "get_point_inside_textfield()", &str
)) {
140 return JSONToPoint(str
, point
);
146 void SetUpOnMainThread() override
{
147 ContentBrowserTest::SetUpOnMainThread();
148 if (!ui::TouchSelectionMenuRunner::GetInstance())
149 menu_runner_
.reset(new TestTouchSelectionMenuRunner
);
152 void TearDownOnMainThread() override
{
153 menu_runner_
= nullptr;
154 ContentBrowserTest::TearDownOnMainThread();
157 scoped_ptr
<TestTouchSelectionMenuRunner
> menu_runner_
;
159 DISALLOW_COPY_AND_ASSIGN(TouchSelectionControllerClientAuraTest
);
162 // Tests if long-pressing on a text brings up selection handles and the quick
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
));
176 EXPECT_EQ(ui::TouchSelectionController::INACTIVE
,
177 rwhva
->selection_controller()->active_status());
178 EXPECT_FALSE(ui::TouchSelectionMenuRunner::GetInstance()->IsRunning());
180 // Long-press on the text and wait for handles to appear.
181 selection_controller_client
->InitWaitForSelectionEvent(
182 ui::SELECTION_HANDLES_SHOWN
);
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
);
191 selection_controller_client
->Wait();
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());
199 // Tests if tapping in a textfield brings up the insertion handle and the quick
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
));
213 EXPECT_EQ(ui::TouchSelectionController::INACTIVE
,
214 rwhva
->selection_controller()->active_status());
215 EXPECT_FALSE(ui::TouchSelectionMenuRunner::GetInstance()->IsRunning());
217 // Tap inside the textfield and wait for the insertion handle to appear.
218 selection_controller_client
->InitWaitForSelectionEvent(
219 ui::INSERTION_HANDLE_SHOWN
);
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(),
227 rwhva
->OnGestureEvent(&tap
);
229 selection_controller_client
->Wait();
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());
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
));
251 EXPECT_EQ(ui::TouchSelectionController::INACTIVE
,
252 rwhva
->selection_controller()->active_status());
253 EXPECT_FALSE(ui::TouchSelectionMenuRunner::GetInstance()->IsRunning());
255 // Long-press on the text and wait for selection handles to appear.
256 selection_controller_client
->InitWaitForSelectionEvent(
257 ui::SELECTION_HANDLES_SHOWN
);
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
);
266 selection_controller_client
->Wait();
268 EXPECT_EQ(ui::TouchSelectionController::SELECTION_ACTIVE
,
269 rwhva
->selection_controller()->active_status());
270 EXPECT_TRUE(ui::TouchSelectionMenuRunner::GetInstance()->IsRunning());
272 ui::test::EventGenerator
generator(
273 web_contents
->GetContentNativeView()->GetRootWindow(),
274 web_contents
->GetContentNativeView());
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());
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());
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());
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());
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());
316 EXPECT_EQ(ui::TouchSelectionController::INACTIVE
,
317 rwhva
->selection_controller()->active_status());
318 EXPECT_FALSE(ui::TouchSelectionMenuRunner::GetInstance()->IsRunning());
320 // Long-press on the text and wait for selection handles to appear.
321 selection_controller_client
->InitWaitForSelectionEvent(
322 ui::SELECTION_HANDLES_SHOWN
);
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
);
331 selection_controller_client
->Wait();
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());
338 // Put a finger down: the quick menu should go away, while touch handles stay
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());
348 // Start scrolling: touch handles should get hidden, while touch selection is
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());
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());
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());
379 // Tests if touch selection gets deactivated after an overscroll completes.
380 IN_PROC_BROWSER_TEST_F(TouchSelectionControllerClientAuraTest
,
381 HiddenAfterOverscroll
) {
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
));
393 EXPECT_EQ(ui::TouchSelectionController::INACTIVE
,
394 rwhva
->selection_controller()->active_status());
395 EXPECT_FALSE(ui::TouchSelectionMenuRunner::GetInstance()->IsRunning());
397 // Long-press on the text and wait for touch handles to appear.
398 selection_controller_client
->InitWaitForSelectionEvent(
399 ui::SELECTION_HANDLES_SHOWN
);
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
);
408 selection_controller_client
->Wait();
410 EXPECT_EQ(ui::TouchSelectionController::SELECTION_ACTIVE
,
411 rwhva
->selection_controller()->active_status());
412 EXPECT_TRUE(ui::TouchSelectionMenuRunner::GetInstance()->IsRunning());
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
);
419 ui::GestureEvent
scroll_begin(
420 10, 10, 0, ui::EventTimeForNow(),
421 ui::GestureEventDetails(ui::ET_GESTURE_SCROLL_BEGIN
));
422 rwhva
->OnGestureEvent(&scroll_begin
);
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
);
429 ui::GestureEvent
scroll_end(
430 210, 10, 0, ui::EventTimeForNow(),
431 ui::GestureEventDetails(ui::ET_GESTURE_SCROLL_END
));
432 rwhva
->OnGestureEvent(&scroll_end
);
434 selection_controller_client
->Wait();
436 EXPECT_EQ(ui::TouchSelectionController::INACTIVE
,
437 rwhva
->selection_controller()->active_status());
438 EXPECT_FALSE(ui::TouchSelectionMenuRunner::GetInstance()->IsRunning());
441 } // namespace content