omnibox_view_views_browsertest.cc revision 46d4c2bc3267f3f028f39e7e311b0f89aba2e4fd
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.
4
5#include "chrome/browser/ui/views/omnibox/omnibox_view_views.h"
6
7#include "base/command_line.h"
8#include "chrome/browser/ui/browser.h"
9#include "chrome/browser/ui/browser_commands.h"
10#include "chrome/browser/ui/browser_window.h"
11#include "chrome/browser/ui/omnibox/location_bar.h"
12#include "chrome/browser/ui/omnibox/omnibox_popup_model.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/test/base/in_process_browser_test.h"
17#include "chrome/test/base/interactive_test_utils.h"
18#include "grit/generated_resources.h"
19#include "ui/aura/test/event_generator.h"
20#include "ui/aura/window.h"
21#include "ui/aura/window_tree_host.h"
22#include "ui/base/clipboard/clipboard.h"
23#include "ui/base/clipboard/scoped_clipboard_writer.h"
24#include "ui/base/test/ui_controls.h"
25#include "ui/base/ui_base_switches.h"
26#include "ui/events/event_processor.h"
27#include "ui/events/event_utils.h"
28#include "ui/views/controls/textfield/textfield_test_api.h"
29
30class OmniboxViewViewsTest : public InProcessBrowserTest {
31 protected:
32  OmniboxViewViewsTest() {}
33
34  static void GetOmniboxViewForBrowser(const Browser* browser,
35                                       OmniboxView** omnibox_view) {
36    BrowserWindow* window = browser->window();
37    ASSERT_TRUE(window);
38    LocationBar* location_bar = window->GetLocationBar();
39    ASSERT_TRUE(location_bar);
40    *omnibox_view = location_bar->GetOmniboxView();
41    ASSERT_TRUE(*omnibox_view);
42  }
43
44  // Move the mouse to the center of the browser window and left-click.
45  void ClickBrowserWindowCenter() {
46    ASSERT_TRUE(ui_test_utils::SendMouseMoveSync(
47        BrowserView::GetBrowserViewForBrowser(
48            browser())->GetBoundsInScreen().CenterPoint()));
49    ASSERT_TRUE(ui_test_utils::SendMouseEventsSync(ui_controls::LEFT,
50                                                   ui_controls::DOWN));
51    ASSERT_TRUE(
52        ui_test_utils::SendMouseEventsSync(ui_controls::LEFT, ui_controls::UP));
53  }
54
55  // Press and release the mouse at the specified locations.  If
56  // |release_offset| differs from |press_offset|, the mouse will be moved
57  // between the press and release.
58  void Click(ui_controls::MouseButton button,
59             const gfx::Point& press_location,
60             const gfx::Point& release_location) {
61    ASSERT_TRUE(ui_test_utils::SendMouseMoveSync(press_location));
62    ASSERT_TRUE(ui_test_utils::SendMouseEventsSync(button, ui_controls::DOWN));
63
64    if (press_location != release_location)
65      ASSERT_TRUE(ui_test_utils::SendMouseMoveSync(release_location));
66    ASSERT_TRUE(ui_test_utils::SendMouseEventsSync(button, ui_controls::UP));
67  }
68
69  // Tap the center of the browser window.
70  void TapBrowserWindowCenter() {
71    gfx::Point center = BrowserView::GetBrowserViewForBrowser(
72        browser())->GetBoundsInScreen().CenterPoint();
73    aura::test::EventGenerator generator(browser()->window()->
74        GetNativeWindow()->GetRootWindow());
75    generator.GestureTapAt(center);
76  }
77
78  // Touch down and release at the specified locations.
79  void Tap(const gfx::Point& press_location,
80           const gfx::Point& release_location) {
81    ui::EventProcessor* dispatcher =
82        browser()->window()->GetNativeWindow()->GetHost()->event_processor();
83
84    base::TimeDelta timestamp = ui::EventTimeForNow();
85    ui::TouchEvent press(
86        ui::ET_TOUCH_PRESSED, press_location, 5, timestamp);
87    ui::EventDispatchDetails details = dispatcher->OnEventFromSource(&press);
88    ASSERT_FALSE(details.dispatcher_destroyed);
89
90    if (press_location != release_location) {
91      timestamp += base::TimeDelta::FromMilliseconds(10);
92      ui::TouchEvent move(
93          ui::ET_TOUCH_MOVED, release_location, 5, timestamp);
94      details = dispatcher->OnEventFromSource(&move);
95    }
96
97    timestamp += base::TimeDelta::FromMilliseconds(50);
98    ui::TouchEvent release(
99        ui::ET_TOUCH_RELEASED, release_location, 5, timestamp);
100    details = dispatcher->OnEventFromSource(&release);
101    ASSERT_FALSE(details.dispatcher_destroyed);
102  }
103
104 private:
105  // InProcessBrowserTest:
106  virtual void SetUpOnMainThread() OVERRIDE {
107    ASSERT_TRUE(ui_test_utils::BringBrowserWindowToFront(browser()));
108    chrome::FocusLocationBar(browser());
109    ASSERT_TRUE(ui_test_utils::IsViewFocused(browser(), VIEW_ID_OMNIBOX));
110  }
111
112  DISALLOW_COPY_AND_ASSIGN(OmniboxViewViewsTest);
113};
114
115IN_PROC_BROWSER_TEST_F(OmniboxViewViewsTest, PasteAndGoDoesNotLeavePopupOpen) {
116  OmniboxView* view = NULL;
117  ASSERT_NO_FATAL_FAILURE(GetOmniboxViewForBrowser(browser(), &view));
118  OmniboxViewViews* omnibox_view_views = static_cast<OmniboxViewViews*>(view);
119
120  // Put an URL on the clipboard.
121  {
122    ui::ScopedClipboardWriter clipboard_writer(
123        ui::Clipboard::GetForCurrentThread(), ui::CLIPBOARD_TYPE_COPY_PASTE);
124    clipboard_writer.WriteURL(base::ASCIIToUTF16("http://www.example.com/"));
125  }
126
127  // Paste and go.
128  omnibox_view_views->ExecuteCommand(IDS_PASTE_AND_GO, ui::EF_NONE);
129
130  // The popup should not be open.
131  EXPECT_FALSE(view->model()->popup_model()->IsOpen());
132}
133
134IN_PROC_BROWSER_TEST_F(OmniboxViewViewsTest, 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/"));
138
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());
143
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());
152
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());
157
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());
163
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());
172
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());
180
181  // Middle-clicking should not be handled by the omnibox.
182  ASSERT_NO_FATAL_FAILURE(ClickBrowserWindowCenter());
183  ASSERT_NO_FATAL_FAILURE(Click(ui_controls::MIDDLE,
184                                click_location, click_location));
185  EXPECT_FALSE(ui_test_utils::IsViewFocused(browser(), VIEW_ID_OMNIBOX));
186  EXPECT_FALSE(omnibox_view->IsSelectAll());
187}
188
189IN_PROC_BROWSER_TEST_F(OmniboxViewViewsTest, SelectAllOnTap) {
190  OmniboxView* omnibox_view = NULL;
191  ASSERT_NO_FATAL_FAILURE(GetOmniboxViewForBrowser(browser(), &omnibox_view));
192  omnibox_view->SetUserText(base::ASCIIToUTF16("http://www.google.com/"));
193
194  // Take the focus away from the omnibox.
195  ASSERT_NO_FATAL_FAILURE(TapBrowserWindowCenter());
196  EXPECT_FALSE(ui_test_utils::IsViewFocused(browser(), VIEW_ID_OMNIBOX));
197  EXPECT_FALSE(omnibox_view->IsSelectAll());
198
199  // Tapping in the omnibox should take focus and select all text.
200  const gfx::Rect omnibox_bounds = BrowserView::GetBrowserViewForBrowser(
201      browser())->GetViewByID(VIEW_ID_OMNIBOX)->GetBoundsInScreen();
202  const gfx::Point tap_location = omnibox_bounds.CenterPoint();
203  ASSERT_NO_FATAL_FAILURE(Tap(tap_location, tap_location));
204  EXPECT_TRUE(ui_test_utils::IsViewFocused(browser(), VIEW_ID_OMNIBOX));
205  EXPECT_TRUE(omnibox_view->IsSelectAll());
206
207  // Tapping in another view should clear focus and the selection.
208  ASSERT_NO_FATAL_FAILURE(TapBrowserWindowCenter());
209  EXPECT_FALSE(ui_test_utils::IsViewFocused(browser(), VIEW_ID_OMNIBOX));
210  EXPECT_FALSE(omnibox_view->IsSelectAll());
211
212  // Tapping in the omnibox again should take focus and select all text again.
213  ASSERT_NO_FATAL_FAILURE(Tap(tap_location, tap_location));
214  EXPECT_TRUE(ui_test_utils::IsViewFocused(browser(), VIEW_ID_OMNIBOX));
215  EXPECT_TRUE(omnibox_view->IsSelectAll());
216
217  // Tapping another omnibox spot should keep focus and selection.
218  omnibox_view->SelectAll(false);
219  const gfx::Point tap2_location = omnibox_bounds.origin() +
220      gfx::Vector2d(omnibox_bounds.width() / 4, omnibox_bounds.height() / 4);
221  ASSERT_NO_FATAL_FAILURE(Tap(tap2_location, tap2_location));
222  EXPECT_TRUE(ui_test_utils::IsViewFocused(browser(), VIEW_ID_OMNIBOX));
223  // We don't test if the all text is selected because it depends on whether or
224  // not there was text under the tap, which appears to be flaky.
225
226  // Take the focus away and tap in the omnibox again, but drag a bit before
227  // releasing.  We should focus the omnibox but not select all of its text.
228  ASSERT_NO_FATAL_FAILURE(TapBrowserWindowCenter());
229  ASSERT_NO_FATAL_FAILURE(Tap(tap_location, tap2_location));
230  EXPECT_TRUE(ui_test_utils::IsViewFocused(browser(), VIEW_ID_OMNIBOX));
231  EXPECT_FALSE(omnibox_view->IsSelectAll());
232}
233
234IN_PROC_BROWSER_TEST_F(OmniboxViewViewsTest, SelectAllOnTabToFocus) {
235  OmniboxView* omnibox_view = NULL;
236  ASSERT_NO_FATAL_FAILURE(GetOmniboxViewForBrowser(browser(), &omnibox_view));
237  ui_test_utils::NavigateToURL(browser(), GURL("http://www.google.com/"));
238  // RevertAll after navigation to invalidate the selection range saved on blur.
239  omnibox_view->RevertAll();
240  EXPECT_FALSE(ui_test_utils::IsViewFocused(browser(), VIEW_ID_OMNIBOX));
241  EXPECT_FALSE(omnibox_view->IsSelectAll());
242
243  // Pressing tab to focus the omnibox should select all text.
244  while (!ui_test_utils::IsViewFocused(browser(), VIEW_ID_OMNIBOX)) {
245    ASSERT_TRUE(ui_test_utils::SendKeyPressSync(browser(), ui::VKEY_TAB,
246                                                false, false, false, false));
247  }
248  EXPECT_TRUE(ui_test_utils::IsViewFocused(browser(), VIEW_ID_OMNIBOX));
249  EXPECT_TRUE(omnibox_view->IsSelectAll());
250}
251
252IN_PROC_BROWSER_TEST_F(OmniboxViewViewsTest, CloseOmniboxPopupOnTextDrag) {
253  OmniboxView* omnibox_view = NULL;
254  ASSERT_NO_FATAL_FAILURE(GetOmniboxViewForBrowser(browser(), &omnibox_view));
255  OmniboxViewViews* omnibox_view_views =
256      static_cast<OmniboxViewViews*>(omnibox_view);
257
258  // Populate suggestions for the omnibox popup.
259  AutocompleteController* autocomplete_controller =
260      omnibox_view->model()->popup_model()->autocomplete_controller();
261  AutocompleteResult& results = autocomplete_controller->result_;
262  ACMatches matches;
263  AutocompleteMatch match;
264  match.destination_url = GURL("http://autocomplete-result/");
265  match.allowed_to_be_default_match = true;
266  match.type = AutocompleteMatchType::HISTORY_TITLE;
267  match.relevance = 500;
268  matches.push_back(match);
269  match.destination_url = GURL("http://autocomplete-result2/");
270  matches.push_back(match);
271  results.AppendMatches(matches);
272  results.SortAndCull(AutocompleteInput(), browser()->profile());
273
274  // The omnibox popup should open with suggestions displayed.
275  omnibox_view->model()->popup_model()->OnResultChanged();
276  EXPECT_TRUE(omnibox_view->model()->popup_model()->IsOpen());
277
278  // The omnibox text should be selected.
279  EXPECT_TRUE(omnibox_view->IsSelectAll());
280
281  // Simulate a mouse click before dragging the mouse.
282  gfx::Point point(omnibox_view_views->x(), omnibox_view_views->y());
283  ui::MouseEvent pressed(ui::ET_MOUSE_PRESSED, point, point,
284                         ui::EF_LEFT_MOUSE_BUTTON, ui::EF_LEFT_MOUSE_BUTTON);
285  omnibox_view_views->OnMousePressed(pressed);
286  EXPECT_TRUE(omnibox_view->model()->popup_model()->IsOpen());
287
288  // Simulate a mouse drag of the omnibox text, and the omnibox should close.
289  ui::MouseEvent dragged(ui::ET_MOUSE_DRAGGED, point, point,
290                         ui::EF_LEFT_MOUSE_BUTTON, 0);
291  omnibox_view_views->OnMouseDragged(dragged);
292
293  EXPECT_FALSE(omnibox_view->model()->popup_model()->IsOpen());
294}
295
296IN_PROC_BROWSER_TEST_F(OmniboxViewViewsTest, BackgroundIsOpaque) {
297  // The omnibox text should be rendered on an opaque background. Otherwise, we
298  // can't use subpixel rendering.
299  BrowserWindowTesting* window = browser()->window()->GetBrowserWindowTesting();
300  ASSERT_TRUE(window);
301  OmniboxViewViews* view = window->GetLocationBarView()->omnibox_view();
302  ASSERT_TRUE(view);
303  EXPECT_FALSE(view->GetRenderText()->background_is_transparent());
304}
305
306// Tests if executing a command hides touch editing handles.
307IN_PROC_BROWSER_TEST_F(OmniboxViewViewsTest,
308                       DeactivateTouchEditingOnExecuteCommand) {
309  CommandLine::ForCurrentProcess()->AppendSwitch(switches::kEnableTouchEditing);
310
311  OmniboxView* view = NULL;
312  ASSERT_NO_FATAL_FAILURE(GetOmniboxViewForBrowser(browser(), &view));
313  OmniboxViewViews* omnibox_view_views = static_cast<OmniboxViewViews*>(view);
314  views::TextfieldTestApi textfield_test_api(omnibox_view_views);
315
316  // Put a URL on the clipboard. It is written to the clipboard upon destruction
317  // of the writer.
318  {
319    ui::ScopedClipboardWriter clipboard_writer(
320        ui::Clipboard::GetForCurrentThread(),
321        ui::CLIPBOARD_TYPE_COPY_PASTE);
322    clipboard_writer.WriteURL(base::ASCIIToUTF16("http://www.example.com/"));
323  }
324
325  // Tap to activate touch editing.
326  gfx::Point omnibox_center =
327      omnibox_view_views->GetBoundsInScreen().CenterPoint();
328  Tap(omnibox_center, omnibox_center);
329  EXPECT_TRUE(textfield_test_api.touch_selection_controller());
330
331  // Execute a command and check if it deactivate touch editing. Paste & Go is
332  // chosen since it is specific to Omnibox and its execution wouldn't be
333  // delgated to the base Textfield class.
334  omnibox_view_views->ExecuteCommand(IDS_PASTE_AND_GO, ui::EF_NONE);
335  EXPECT_FALSE(textfield_test_api.touch_selection_controller());
336}
337