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: 33 OmniboxViewViewsTest() {} 34 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. 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. 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. 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. 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: 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 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 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 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 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 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 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. 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 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