1 // Copyright (c) 2013 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 "chrome/browser/ui/views/omnibox/omnibox_view_views.h"
7 #include "base/command_line.h"
8 #include "chrome/browser/search_engines/template_url_service_factory.h"
9 #include "chrome/browser/ui/browser.h"
10 #include "chrome/browser/ui/browser_commands.h"
11 #include "chrome/browser/ui/browser_window.h"
12 #include "chrome/browser/ui/location_bar/location_bar.h"
13 #include "chrome/browser/ui/view_ids.h"
14 #include "chrome/browser/ui/views/frame/browser_view.h"
15 #include "chrome/browser/ui/views/location_bar/location_bar_view.h"
16 #include "chrome/browser/ui/views/toolbar/toolbar_view.h"
17 #include "chrome/grit/generated_resources.h"
18 #include "chrome/test/base/in_process_browser_test.h"
19 #include "chrome/test/base/interactive_test_utils.h"
20 #include "components/omnibox/browser/omnibox_popup_model.h"
21 #include "ui/base/clipboard/clipboard.h"
22 #include "ui/base/clipboard/scoped_clipboard_writer.h"
23 #include "ui/base/ime/input_method.h"
24 #include "ui/base/ime/text_input_client.h"
25 #include "ui/base/test/ui_controls.h"
26 #include "ui/base/ui_base_switches.h"
27 #include "ui/events/event_processor.h"
28 #include "ui/events/event_utils.h"
29 #include "ui/events/test/event_generator.h"
30 #include "ui/views/controls/textfield/textfield_test_api.h"
34 void SetClipboardText(ui::ClipboardType type
, const std::string
& text
) {
35 ui::ScopedClipboardWriter(type
).WriteText(base::ASCIIToUTF16(text
));
40 class OmniboxViewViewsTest
: public InProcessBrowserTest
{
42 OmniboxViewViewsTest() {}
44 static void GetOmniboxViewForBrowser(const Browser
* browser
,
45 OmniboxView
** omnibox_view
) {
46 BrowserWindow
* window
= browser
->window();
48 LocationBar
* location_bar
= window
->GetLocationBar();
49 ASSERT_TRUE(location_bar
);
50 *omnibox_view
= location_bar
->GetOmniboxView();
51 ASSERT_TRUE(*omnibox_view
);
54 // Move the mouse to the center of the browser window and left-click.
55 void ClickBrowserWindowCenter() {
56 ASSERT_TRUE(ui_test_utils::SendMouseMoveSync(
57 BrowserView::GetBrowserViewForBrowser(
58 browser())->GetBoundsInScreen().CenterPoint()));
59 ASSERT_TRUE(ui_test_utils::SendMouseEventsSync(ui_controls::LEFT
,
62 ui_test_utils::SendMouseEventsSync(ui_controls::LEFT
, ui_controls::UP
));
65 // Press and release the mouse at the specified locations. If
66 // |release_offset| differs from |press_offset|, the mouse will be moved
67 // between the press and release.
68 void Click(ui_controls::MouseButton button
,
69 const gfx::Point
& press_location
,
70 const gfx::Point
& release_location
) {
71 ASSERT_TRUE(ui_test_utils::SendMouseMoveSync(press_location
));
72 ASSERT_TRUE(ui_test_utils::SendMouseEventsSync(button
, ui_controls::DOWN
));
74 if (press_location
!= release_location
)
75 ASSERT_TRUE(ui_test_utils::SendMouseMoveSync(release_location
));
76 ASSERT_TRUE(ui_test_utils::SendMouseEventsSync(button
, ui_controls::UP
));
79 // Tap the center of the browser window.
80 void TapBrowserWindowCenter() {
81 gfx::Point center
= BrowserView::GetBrowserViewForBrowser(
82 browser())->GetBoundsInScreen().CenterPoint();
83 ui::test::EventGenerator
generator(browser()->window()->GetNativeWindow());
84 generator
.GestureTapAt(center
);
87 // Touch down and release at the specified locations.
88 void Tap(const gfx::Point
& press_location
,
89 const gfx::Point
& release_location
) {
90 ui::test::EventGenerator
generator(browser()->window()->GetNativeWindow());
91 if (press_location
== release_location
) {
92 generator
.GestureTapAt(press_location
);
94 generator
.GestureScrollSequence(press_location
,
96 base::TimeDelta::FromMilliseconds(10),
102 // InProcessBrowserTest:
103 void SetUpOnMainThread() override
{
104 ASSERT_TRUE(ui_test_utils::BringBrowserWindowToFront(browser()));
105 chrome::FocusLocationBar(browser());
106 ASSERT_TRUE(ui_test_utils::IsViewFocused(browser(), VIEW_ID_OMNIBOX
));
109 DISALLOW_COPY_AND_ASSIGN(OmniboxViewViewsTest
);
112 IN_PROC_BROWSER_TEST_F(OmniboxViewViewsTest
, PasteAndGoDoesNotLeavePopupOpen
) {
113 OmniboxView
* view
= NULL
;
114 ASSERT_NO_FATAL_FAILURE(GetOmniboxViewForBrowser(browser(), &view
));
115 OmniboxViewViews
* omnibox_view_views
= static_cast<OmniboxViewViews
*>(view
);
117 // Put an URL on the clipboard.
118 SetClipboardText(ui::CLIPBOARD_TYPE_COPY_PASTE
, "http://www.example.com/");
121 omnibox_view_views
->ExecuteCommand(IDS_PASTE_AND_GO
, ui::EF_NONE
);
123 // The popup should not be open.
124 EXPECT_FALSE(view
->model()->popup_model()->IsOpen());
128 // flaky on Windows - http://crbug.com/523255
129 #define MAYBE_SelectAllOnClick DISABLED_SelectAllOnClick
131 #define MAYBE_SelectAllOnClick SelectAllOnClick
134 IN_PROC_BROWSER_TEST_F(OmniboxViewViewsTest
, MAYBE_SelectAllOnClick
) {
135 OmniboxView
* omnibox_view
= NULL
;
136 ASSERT_NO_FATAL_FAILURE(GetOmniboxViewForBrowser(browser(), &omnibox_view
));
137 omnibox_view
->SetUserText(base::ASCIIToUTF16("http://www.google.com/"));
139 // Take the focus away from the omnibox.
140 ASSERT_NO_FATAL_FAILURE(ClickBrowserWindowCenter());
141 EXPECT_FALSE(ui_test_utils::IsViewFocused(browser(), VIEW_ID_OMNIBOX
));
142 EXPECT_FALSE(omnibox_view
->IsSelectAll());
144 // Clicking in the omnibox should take focus and select all text.
145 const gfx::Rect omnibox_bounds
= BrowserView::GetBrowserViewForBrowser(
146 browser())->GetViewByID(VIEW_ID_OMNIBOX
)->GetBoundsInScreen();
147 const gfx::Point click_location
= omnibox_bounds
.CenterPoint();
148 ASSERT_NO_FATAL_FAILURE(Click(ui_controls::LEFT
,
149 click_location
, click_location
));
150 EXPECT_TRUE(ui_test_utils::IsViewFocused(browser(), VIEW_ID_OMNIBOX
));
151 EXPECT_TRUE(omnibox_view
->IsSelectAll());
153 // Clicking in another view should clear focus and the selection.
154 ASSERT_NO_FATAL_FAILURE(ClickBrowserWindowCenter());
155 EXPECT_FALSE(ui_test_utils::IsViewFocused(browser(), VIEW_ID_OMNIBOX
));
156 EXPECT_FALSE(omnibox_view
->IsSelectAll());
158 // Clicking in the omnibox again should take focus and select all text again.
159 ASSERT_NO_FATAL_FAILURE(Click(ui_controls::LEFT
,
160 click_location
, click_location
));
161 EXPECT_TRUE(ui_test_utils::IsViewFocused(browser(), VIEW_ID_OMNIBOX
));
162 EXPECT_TRUE(omnibox_view
->IsSelectAll());
164 // Clicking another omnibox spot should keep focus but clear the selection.
165 omnibox_view
->SelectAll(false);
166 const gfx::Point click2_location
= omnibox_bounds
.origin() +
167 gfx::Vector2d(omnibox_bounds
.width() / 4, omnibox_bounds
.height() / 4);
168 ASSERT_NO_FATAL_FAILURE(Click(ui_controls::LEFT
,
169 click2_location
, click2_location
));
170 EXPECT_TRUE(ui_test_utils::IsViewFocused(browser(), VIEW_ID_OMNIBOX
));
171 EXPECT_FALSE(omnibox_view
->IsSelectAll());
173 // Take the focus away and click in the omnibox again, but drag a bit before
174 // releasing. We should focus the omnibox but not select all of its text.
175 ASSERT_NO_FATAL_FAILURE(ClickBrowserWindowCenter());
176 ASSERT_NO_FATAL_FAILURE(Click(ui_controls::LEFT
,
177 click_location
, click2_location
));
178 EXPECT_TRUE(ui_test_utils::IsViewFocused(browser(), VIEW_ID_OMNIBOX
));
179 EXPECT_FALSE(omnibox_view
->IsSelectAll());
181 // Middle-click is only handled on Linux, by pasting the selection clipboard
182 // and moving the cursor after the pasted text instead of selecting-all.
183 ASSERT_NO_FATAL_FAILURE(ClickBrowserWindowCenter());
184 ASSERT_NO_FATAL_FAILURE(Click(ui_controls::MIDDLE
,
185 click_location
, click_location
));
186 #if defined(OS_LINUX) && !defined(OS_CHROMEOS)
187 EXPECT_TRUE(ui_test_utils::IsViewFocused(browser(), VIEW_ID_OMNIBOX
));
188 EXPECT_FALSE(omnibox_view
->IsSelectAll());
190 EXPECT_FALSE(ui_test_utils::IsViewFocused(browser(), VIEW_ID_OMNIBOX
));
191 EXPECT_FALSE(omnibox_view
->IsSelectAll());
192 #endif // OS_LINUX && !OS_CHROMEOS
195 #if defined(OS_LINUX) && !defined(OS_CHROMEOS)
196 IN_PROC_BROWSER_TEST_F(OmniboxViewViewsTest
, SelectionClipboard
) {
197 OmniboxView
* omnibox_view
= NULL
;
198 ASSERT_NO_FATAL_FAILURE(GetOmniboxViewForBrowser(browser(), &omnibox_view
));
199 omnibox_view
->SetUserText(base::ASCIIToUTF16("http://www.google.com/"));
200 OmniboxViewViews
* omnibox_view_views
=
201 static_cast<OmniboxViewViews
*>(omnibox_view
);
202 ASSERT_TRUE(omnibox_view_views
);
203 gfx::RenderText
* render_text
= omnibox_view_views
->GetRenderText();
205 // Take the focus away from the omnibox.
206 ASSERT_NO_FATAL_FAILURE(TapBrowserWindowCenter());
207 EXPECT_FALSE(ui_test_utils::IsViewFocused(browser(), VIEW_ID_OMNIBOX
));
208 EXPECT_FALSE(omnibox_view
->IsSelectAll());
210 size_t cursor_position
= 14;
211 int cursor_x
= render_text
->GetCursorBounds(
212 gfx::SelectionModel(cursor_position
, gfx::CURSOR_FORWARD
), false).x();
213 gfx::Point click_location
= omnibox_view_views
->GetBoundsInScreen().origin();
214 click_location
.Offset(cursor_x
+ render_text
->display_rect().x(),
215 omnibox_view_views
->height() / 2);
217 // Middle click focuses the omnibox, pastes, and sets a trailing cursor.
218 // Select-all on focus shouldn't alter the selection clipboard or cursor.
219 SetClipboardText(ui::CLIPBOARD_TYPE_SELECTION
, "123");
220 ASSERT_NO_FATAL_FAILURE(Click(ui_controls::MIDDLE
,
221 click_location
, click_location
));
222 EXPECT_TRUE(ui_test_utils::IsViewFocused(browser(), VIEW_ID_OMNIBOX
));
223 EXPECT_FALSE(omnibox_view
->IsSelectAll());
224 EXPECT_EQ(base::ASCIIToUTF16("http://www.goo123gle.com/"),
225 omnibox_view
->GetText());
226 EXPECT_EQ(17U, omnibox_view_views
->GetCursorPosition());
228 // Middle clicking again, with focus, pastes and updates the cursor.
229 SetClipboardText(ui::CLIPBOARD_TYPE_SELECTION
, "4567");
230 ASSERT_NO_FATAL_FAILURE(Click(ui_controls::MIDDLE
,
231 click_location
, click_location
));
232 EXPECT_TRUE(ui_test_utils::IsViewFocused(browser(), VIEW_ID_OMNIBOX
));
233 EXPECT_FALSE(omnibox_view
->IsSelectAll());
234 EXPECT_EQ(base::ASCIIToUTF16("http://www.goo4567123gle.com/"),
235 omnibox_view
->GetText());
236 EXPECT_EQ(18U, omnibox_view_views
->GetCursorPosition());
238 #endif // OS_LINUX && !OS_CHROMEOS
240 IN_PROC_BROWSER_TEST_F(OmniboxViewViewsTest
, SelectAllOnTap
) {
241 OmniboxView
* omnibox_view
= NULL
;
242 ASSERT_NO_FATAL_FAILURE(GetOmniboxViewForBrowser(browser(), &omnibox_view
));
243 omnibox_view
->SetUserText(base::ASCIIToUTF16("http://www.google.com/"));
245 // Take the focus away from the omnibox.
246 ASSERT_NO_FATAL_FAILURE(TapBrowserWindowCenter());
247 EXPECT_FALSE(ui_test_utils::IsViewFocused(browser(), VIEW_ID_OMNIBOX
));
248 EXPECT_FALSE(omnibox_view
->IsSelectAll());
250 // Tapping in the omnibox should take focus and select all text.
251 const gfx::Rect omnibox_bounds
= BrowserView::GetBrowserViewForBrowser(
252 browser())->GetViewByID(VIEW_ID_OMNIBOX
)->GetBoundsInScreen();
253 const gfx::Point tap_location
= omnibox_bounds
.CenterPoint();
254 ASSERT_NO_FATAL_FAILURE(Tap(tap_location
, tap_location
));
255 EXPECT_TRUE(ui_test_utils::IsViewFocused(browser(), VIEW_ID_OMNIBOX
));
256 EXPECT_TRUE(omnibox_view
->IsSelectAll());
258 // Tapping in another view should clear focus and the selection.
259 ASSERT_NO_FATAL_FAILURE(TapBrowserWindowCenter());
260 EXPECT_FALSE(ui_test_utils::IsViewFocused(browser(), VIEW_ID_OMNIBOX
));
261 EXPECT_FALSE(omnibox_view
->IsSelectAll());
263 // Tapping in the omnibox again should take focus and select all text again.
264 ASSERT_NO_FATAL_FAILURE(Tap(tap_location
, tap_location
));
265 EXPECT_TRUE(ui_test_utils::IsViewFocused(browser(), VIEW_ID_OMNIBOX
));
266 EXPECT_TRUE(omnibox_view
->IsSelectAll());
268 // Tapping another omnibox spot should keep focus and selection.
269 omnibox_view
->SelectAll(false);
270 const gfx::Point tap2_location
= omnibox_bounds
.origin() +
271 gfx::Vector2d(omnibox_bounds
.width() / 4, omnibox_bounds
.height() / 4);
272 ASSERT_NO_FATAL_FAILURE(Tap(tap2_location
, tap2_location
));
273 EXPECT_TRUE(ui_test_utils::IsViewFocused(browser(), VIEW_ID_OMNIBOX
));
274 // We don't test if the all text is selected because it depends on whether or
275 // not there was text under the tap, which appears to be flaky.
277 // Take the focus away and tap in the omnibox again, but drag a bit before
278 // releasing. We should focus the omnibox but not select all of its text.
279 ASSERT_NO_FATAL_FAILURE(TapBrowserWindowCenter());
280 ASSERT_NO_FATAL_FAILURE(Tap(tap_location
, tap2_location
));
281 EXPECT_TRUE(ui_test_utils::IsViewFocused(browser(), VIEW_ID_OMNIBOX
));
282 EXPECT_FALSE(omnibox_view
->IsSelectAll());
285 IN_PROC_BROWSER_TEST_F(OmniboxViewViewsTest
, SelectAllOnTabToFocus
) {
286 OmniboxView
* omnibox_view
= NULL
;
287 ASSERT_NO_FATAL_FAILURE(GetOmniboxViewForBrowser(browser(), &omnibox_view
));
288 ui_test_utils::NavigateToURL(browser(), GURL("http://www.google.com/"));
289 // RevertAll after navigation to invalidate the selection range saved on blur.
290 omnibox_view
->RevertAll();
291 EXPECT_FALSE(ui_test_utils::IsViewFocused(browser(), VIEW_ID_OMNIBOX
));
292 EXPECT_FALSE(omnibox_view
->IsSelectAll());
294 // Pressing tab to focus the omnibox should select all text.
295 while (!ui_test_utils::IsViewFocused(browser(), VIEW_ID_OMNIBOX
)) {
296 ASSERT_TRUE(ui_test_utils::SendKeyPressSync(browser(), ui::VKEY_TAB
,
297 false, false, false, false));
299 EXPECT_TRUE(ui_test_utils::IsViewFocused(browser(), VIEW_ID_OMNIBOX
));
300 EXPECT_TRUE(omnibox_view
->IsSelectAll());
303 IN_PROC_BROWSER_TEST_F(OmniboxViewViewsTest
, CloseOmniboxPopupOnTextDrag
) {
304 OmniboxView
* omnibox_view
= NULL
;
305 ASSERT_NO_FATAL_FAILURE(GetOmniboxViewForBrowser(browser(), &omnibox_view
));
306 OmniboxViewViews
* omnibox_view_views
=
307 static_cast<OmniboxViewViews
*>(omnibox_view
);
309 // Populate suggestions for the omnibox popup.
310 AutocompleteController
* autocomplete_controller
=
311 omnibox_view
->model()->popup_model()->autocomplete_controller();
312 AutocompleteResult
& results
= autocomplete_controller
->result_
;
314 AutocompleteMatch match
;
315 match
.destination_url
= GURL("http://autocomplete-result/");
316 match
.allowed_to_be_default_match
= true;
317 match
.type
= AutocompleteMatchType::HISTORY_TITLE
;
318 match
.relevance
= 500;
319 matches
.push_back(match
);
320 match
.destination_url
= GURL("http://autocomplete-result2/");
321 matches
.push_back(match
);
322 results
.AppendMatches(AutocompleteInput(), matches
);
326 TemplateURLServiceFactory::GetForProfile(browser()->profile()));
328 // The omnibox popup should open with suggestions displayed.
329 omnibox_view
->model()->popup_model()->OnResultChanged();
330 EXPECT_TRUE(omnibox_view
->model()->popup_model()->IsOpen());
332 // The omnibox text should be selected.
333 EXPECT_TRUE(omnibox_view
->IsSelectAll());
335 // Simulate a mouse click before dragging the mouse.
336 gfx::Point
point(omnibox_view_views
->x(), omnibox_view_views
->y());
337 ui::MouseEvent
pressed(ui::ET_MOUSE_PRESSED
, point
, point
,
338 ui::EventTimeForNow(), ui::EF_LEFT_MOUSE_BUTTON
,
339 ui::EF_LEFT_MOUSE_BUTTON
);
340 omnibox_view_views
->OnMousePressed(pressed
);
341 EXPECT_TRUE(omnibox_view
->model()->popup_model()->IsOpen());
343 // Simulate a mouse drag of the omnibox text, and the omnibox should close.
344 ui::MouseEvent
dragged(ui::ET_MOUSE_DRAGGED
, point
, point
,
345 ui::EventTimeForNow(), ui::EF_LEFT_MOUSE_BUTTON
, 0);
346 omnibox_view_views
->OnMouseDragged(dragged
);
348 EXPECT_FALSE(omnibox_view
->model()->popup_model()->IsOpen());
351 IN_PROC_BROWSER_TEST_F(OmniboxViewViewsTest
, BackgroundIsOpaque
) {
352 // The omnibox text should be rendered on an opaque background. Otherwise, we
353 // can't use subpixel rendering.
354 OmniboxViewViews
* view
= BrowserView::GetBrowserViewForBrowser(browser())->
355 toolbar()->location_bar()->omnibox_view();
357 EXPECT_FALSE(view
->GetRenderText()->subpixel_rendering_suppressed());
360 // Tests if executing a command hides touch editing handles.
361 IN_PROC_BROWSER_TEST_F(OmniboxViewViewsTest
,
362 DeactivateTouchEditingOnExecuteCommand
) {
363 base::CommandLine::ForCurrentProcess()->AppendSwitch(
364 switches::kEnableTouchEditing
);
366 OmniboxView
* view
= NULL
;
367 ASSERT_NO_FATAL_FAILURE(GetOmniboxViewForBrowser(browser(), &view
));
368 OmniboxViewViews
* omnibox_view_views
= static_cast<OmniboxViewViews
*>(view
);
369 views::TextfieldTestApi
textfield_test_api(omnibox_view_views
);
371 // Put a URL on the clipboard.
372 SetClipboardText(ui::CLIPBOARD_TYPE_COPY_PASTE
, "http://www.example.com/");
374 // Tap to activate touch editing.
375 gfx::Point omnibox_center
=
376 omnibox_view_views
->GetBoundsInScreen().CenterPoint();
377 Tap(omnibox_center
, omnibox_center
);
378 EXPECT_TRUE(textfield_test_api
.touch_selection_controller());
380 // Execute a command and check if it deactivate touch editing. Paste & Go is
381 // chosen since it is specific to Omnibox and its execution wouldn't be
382 // delgated to the base Textfield class.
383 omnibox_view_views
->ExecuteCommand(IDS_PASTE_AND_GO
, ui::EF_NONE
);
384 EXPECT_FALSE(textfield_test_api
.touch_selection_controller());
387 IN_PROC_BROWSER_TEST_F(OmniboxViewViewsTest
, FocusedTextInputClient
) {
388 chrome::FocusLocationBar(browser());
389 OmniboxView
* view
= NULL
;
390 ASSERT_NO_FATAL_FAILURE(GetOmniboxViewForBrowser(browser(), &view
));
391 OmniboxViewViews
* omnibox_view_views
= static_cast<OmniboxViewViews
*>(view
);
392 ui::InputMethod
* input_method
=
393 omnibox_view_views
->GetWidget()->GetInputMethod();
394 EXPECT_EQ(static_cast<ui::TextInputClient
*>(omnibox_view_views
),
395 input_method
->GetTextInputClient());