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