Home | History | Annotate | Download | only in omnibox
      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/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/browser_window_testing_views.h"
     13 #include "chrome/browser/ui/location_bar/location_bar.h"
     14 #include "chrome/browser/ui/omnibox/omnibox_popup_model.h"
     15 #include "chrome/browser/ui/view_ids.h"
     16 #include "chrome/browser/ui/views/frame/browser_view.h"
     17 #include "chrome/browser/ui/views/location_bar/location_bar_view.h"
     18 #include "chrome/grit/generated_resources.h"
     19 #include "chrome/test/base/in_process_browser_test.h"
     20 #include "chrome/test/base/interactive_test_utils.h"
     21 #include "ui/base/clipboard/clipboard.h"
     22 #include "ui/base/clipboard/scoped_clipboard_writer.h"
     23 #include "ui/base/ime/text_input_focus_manager.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/events/test/event_generator.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     ui::test::EventGenerator generator(browser()->window()->GetNativeWindow());
     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::test::EventGenerator generator(browser()->window()->GetNativeWindow());
     82     if (press_location == release_location) {
     83       generator.GestureTapAt(press_location);
     84     } else {
     85       generator.GestureScrollSequence(press_location,
     86                                       release_location,
     87                                       base::TimeDelta::FromMilliseconds(10),
     88                                       1);
     89     }
     90   }
     91 
     92  private:
     93   // InProcessBrowserTest:
     94   virtual void SetUpOnMainThread() OVERRIDE {
     95     ASSERT_TRUE(ui_test_utils::BringBrowserWindowToFront(browser()));
     96     chrome::FocusLocationBar(browser());
     97     ASSERT_TRUE(ui_test_utils::IsViewFocused(browser(), VIEW_ID_OMNIBOX));
     98   }
     99 
    100   DISALLOW_COPY_AND_ASSIGN(OmniboxViewViewsTest);
    101 };
    102 
    103 IN_PROC_BROWSER_TEST_F(OmniboxViewViewsTest, PasteAndGoDoesNotLeavePopupOpen) {
    104   OmniboxView* view = NULL;
    105   ASSERT_NO_FATAL_FAILURE(GetOmniboxViewForBrowser(browser(), &view));
    106   OmniboxViewViews* omnibox_view_views = static_cast<OmniboxViewViews*>(view);
    107 
    108   // Put an URL on the clipboard.
    109   {
    110     ui::ScopedClipboardWriter clipboard_writer(ui::CLIPBOARD_TYPE_COPY_PASTE);
    111     clipboard_writer.WriteURL(base::ASCIIToUTF16("http://www.example.com/"));
    112   }
    113 
    114   // Paste and go.
    115   omnibox_view_views->ExecuteCommand(IDS_PASTE_AND_GO, ui::EF_NONE);
    116 
    117   // The popup should not be open.
    118   EXPECT_FALSE(view->model()->popup_model()->IsOpen());
    119 }
    120 
    121 IN_PROC_BROWSER_TEST_F(OmniboxViewViewsTest, SelectAllOnClick) {
    122   OmniboxView* omnibox_view = NULL;
    123   ASSERT_NO_FATAL_FAILURE(GetOmniboxViewForBrowser(browser(), &omnibox_view));
    124   omnibox_view->SetUserText(base::ASCIIToUTF16("http://www.google.com/"));
    125 
    126   // Take the focus away from the omnibox.
    127   ASSERT_NO_FATAL_FAILURE(ClickBrowserWindowCenter());
    128   EXPECT_FALSE(ui_test_utils::IsViewFocused(browser(), VIEW_ID_OMNIBOX));
    129   EXPECT_FALSE(omnibox_view->IsSelectAll());
    130 
    131   // Clicking in the omnibox should take focus and select all text.
    132   const gfx::Rect omnibox_bounds = BrowserView::GetBrowserViewForBrowser(
    133         browser())->GetViewByID(VIEW_ID_OMNIBOX)->GetBoundsInScreen();
    134   const gfx::Point click_location = omnibox_bounds.CenterPoint();
    135   ASSERT_NO_FATAL_FAILURE(Click(ui_controls::LEFT,
    136                                 click_location, click_location));
    137   EXPECT_TRUE(ui_test_utils::IsViewFocused(browser(), VIEW_ID_OMNIBOX));
    138   EXPECT_TRUE(omnibox_view->IsSelectAll());
    139 
    140   // Clicking in another view should clear focus and the selection.
    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 again should take focus and select all text again.
    146   ASSERT_NO_FATAL_FAILURE(Click(ui_controls::LEFT,
    147                                 click_location, click_location));
    148   EXPECT_TRUE(ui_test_utils::IsViewFocused(browser(), VIEW_ID_OMNIBOX));
    149   EXPECT_TRUE(omnibox_view->IsSelectAll());
    150 
    151   // Clicking another omnibox spot should keep focus but clear the selection.
    152   omnibox_view->SelectAll(false);
    153   const gfx::Point click2_location = omnibox_bounds.origin() +
    154       gfx::Vector2d(omnibox_bounds.width() / 4, omnibox_bounds.height() / 4);
    155   ASSERT_NO_FATAL_FAILURE(Click(ui_controls::LEFT,
    156                                 click2_location, click2_location));
    157   EXPECT_TRUE(ui_test_utils::IsViewFocused(browser(), VIEW_ID_OMNIBOX));
    158   EXPECT_FALSE(omnibox_view->IsSelectAll());
    159 
    160   // Take the focus away and click in the omnibox again, but drag a bit before
    161   // releasing.  We should focus the omnibox but not select all of its text.
    162   ASSERT_NO_FATAL_FAILURE(ClickBrowserWindowCenter());
    163   ASSERT_NO_FATAL_FAILURE(Click(ui_controls::LEFT,
    164                                 click_location, click2_location));
    165   EXPECT_TRUE(ui_test_utils::IsViewFocused(browser(), VIEW_ID_OMNIBOX));
    166   EXPECT_FALSE(omnibox_view->IsSelectAll());
    167 
    168   // Middle-clicking should not be handled by the omnibox.
    169   ASSERT_NO_FATAL_FAILURE(ClickBrowserWindowCenter());
    170   ASSERT_NO_FATAL_FAILURE(Click(ui_controls::MIDDLE,
    171                                 click_location, click_location));
    172   EXPECT_FALSE(ui_test_utils::IsViewFocused(browser(), VIEW_ID_OMNIBOX));
    173   EXPECT_FALSE(omnibox_view->IsSelectAll());
    174 }
    175 
    176 IN_PROC_BROWSER_TEST_F(OmniboxViewViewsTest, SelectAllOnTap) {
    177   OmniboxView* omnibox_view = NULL;
    178   ASSERT_NO_FATAL_FAILURE(GetOmniboxViewForBrowser(browser(), &omnibox_view));
    179   omnibox_view->SetUserText(base::ASCIIToUTF16("http://www.google.com/"));
    180 
    181   // Take the focus away from the omnibox.
    182   ASSERT_NO_FATAL_FAILURE(TapBrowserWindowCenter());
    183   EXPECT_FALSE(ui_test_utils::IsViewFocused(browser(), VIEW_ID_OMNIBOX));
    184   EXPECT_FALSE(omnibox_view->IsSelectAll());
    185 
    186   // Tapping in the omnibox should take focus and select all text.
    187   const gfx::Rect omnibox_bounds = BrowserView::GetBrowserViewForBrowser(
    188       browser())->GetViewByID(VIEW_ID_OMNIBOX)->GetBoundsInScreen();
    189   const gfx::Point tap_location = omnibox_bounds.CenterPoint();
    190   ASSERT_NO_FATAL_FAILURE(Tap(tap_location, tap_location));
    191   EXPECT_TRUE(ui_test_utils::IsViewFocused(browser(), VIEW_ID_OMNIBOX));
    192   EXPECT_TRUE(omnibox_view->IsSelectAll());
    193 
    194   // Tapping in another view should clear focus and the selection.
    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 again should take focus and select all text again.
    200   ASSERT_NO_FATAL_FAILURE(Tap(tap_location, tap_location));
    201   EXPECT_TRUE(ui_test_utils::IsViewFocused(browser(), VIEW_ID_OMNIBOX));
    202   EXPECT_TRUE(omnibox_view->IsSelectAll());
    203 
    204   // Tapping another omnibox spot should keep focus and selection.
    205   omnibox_view->SelectAll(false);
    206   const gfx::Point tap2_location = omnibox_bounds.origin() +
    207       gfx::Vector2d(omnibox_bounds.width() / 4, omnibox_bounds.height() / 4);
    208   ASSERT_NO_FATAL_FAILURE(Tap(tap2_location, tap2_location));
    209   EXPECT_TRUE(ui_test_utils::IsViewFocused(browser(), VIEW_ID_OMNIBOX));
    210   // We don't test if the all text is selected because it depends on whether or
    211   // not there was text under the tap, which appears to be flaky.
    212 
    213   // Take the focus away and tap in the omnibox again, but drag a bit before
    214   // releasing.  We should focus the omnibox but not select all of its text.
    215   ASSERT_NO_FATAL_FAILURE(TapBrowserWindowCenter());
    216   ASSERT_NO_FATAL_FAILURE(Tap(tap_location, tap2_location));
    217   EXPECT_TRUE(ui_test_utils::IsViewFocused(browser(), VIEW_ID_OMNIBOX));
    218   EXPECT_FALSE(omnibox_view->IsSelectAll());
    219 }
    220 
    221 IN_PROC_BROWSER_TEST_F(OmniboxViewViewsTest, SelectAllOnTabToFocus) {
    222   OmniboxView* omnibox_view = NULL;
    223   ASSERT_NO_FATAL_FAILURE(GetOmniboxViewForBrowser(browser(), &omnibox_view));
    224   ui_test_utils::NavigateToURL(browser(), GURL("http://www.google.com/"));
    225   // RevertAll after navigation to invalidate the selection range saved on blur.
    226   omnibox_view->RevertAll();
    227   EXPECT_FALSE(ui_test_utils::IsViewFocused(browser(), VIEW_ID_OMNIBOX));
    228   EXPECT_FALSE(omnibox_view->IsSelectAll());
    229 
    230   // Pressing tab to focus the omnibox should select all text.
    231   while (!ui_test_utils::IsViewFocused(browser(), VIEW_ID_OMNIBOX)) {
    232     ASSERT_TRUE(ui_test_utils::SendKeyPressSync(browser(), ui::VKEY_TAB,
    233                                                 false, false, false, false));
    234   }
    235   EXPECT_TRUE(ui_test_utils::IsViewFocused(browser(), VIEW_ID_OMNIBOX));
    236   EXPECT_TRUE(omnibox_view->IsSelectAll());
    237 }
    238 
    239 IN_PROC_BROWSER_TEST_F(OmniboxViewViewsTest, CloseOmniboxPopupOnTextDrag) {
    240   OmniboxView* omnibox_view = NULL;
    241   ASSERT_NO_FATAL_FAILURE(GetOmniboxViewForBrowser(browser(), &omnibox_view));
    242   OmniboxViewViews* omnibox_view_views =
    243       static_cast<OmniboxViewViews*>(omnibox_view);
    244 
    245   // Populate suggestions for the omnibox popup.
    246   AutocompleteController* autocomplete_controller =
    247       omnibox_view->model()->popup_model()->autocomplete_controller();
    248   AutocompleteResult& results = autocomplete_controller->result_;
    249   ACMatches matches;
    250   AutocompleteMatch match;
    251   match.destination_url = GURL("http://autocomplete-result/");
    252   match.allowed_to_be_default_match = true;
    253   match.type = AutocompleteMatchType::HISTORY_TITLE;
    254   match.relevance = 500;
    255   matches.push_back(match);
    256   match.destination_url = GURL("http://autocomplete-result2/");
    257   matches.push_back(match);
    258   results.AppendMatches(matches);
    259   results.SortAndCull(
    260       AutocompleteInput(),
    261       TemplateURLServiceFactory::GetForProfile(browser()->profile()));
    262 
    263   // The omnibox popup should open with suggestions displayed.
    264   omnibox_view->model()->popup_model()->OnResultChanged();
    265   EXPECT_TRUE(omnibox_view->model()->popup_model()->IsOpen());
    266 
    267   // The omnibox text should be selected.
    268   EXPECT_TRUE(omnibox_view->IsSelectAll());
    269 
    270   // Simulate a mouse click before dragging the mouse.
    271   gfx::Point point(omnibox_view_views->x(), omnibox_view_views->y());
    272   ui::MouseEvent pressed(ui::ET_MOUSE_PRESSED, point, point,
    273                          ui::EF_LEFT_MOUSE_BUTTON, ui::EF_LEFT_MOUSE_BUTTON);
    274   omnibox_view_views->OnMousePressed(pressed);
    275   EXPECT_TRUE(omnibox_view->model()->popup_model()->IsOpen());
    276 
    277   // Simulate a mouse drag of the omnibox text, and the omnibox should close.
    278   ui::MouseEvent dragged(ui::ET_MOUSE_DRAGGED, point, point,
    279                          ui::EF_LEFT_MOUSE_BUTTON, 0);
    280   omnibox_view_views->OnMouseDragged(dragged);
    281 
    282   EXPECT_FALSE(omnibox_view->model()->popup_model()->IsOpen());
    283 }
    284 
    285 IN_PROC_BROWSER_TEST_F(OmniboxViewViewsTest, BackgroundIsOpaque) {
    286   // The omnibox text should be rendered on an opaque background. Otherwise, we
    287   // can't use subpixel rendering.
    288   BrowserWindowTesting* window = browser()->window()->GetBrowserWindowTesting();
    289   ASSERT_TRUE(window);
    290   OmniboxViewViews* view = window->GetLocationBarView()->omnibox_view();
    291   ASSERT_TRUE(view);
    292   EXPECT_FALSE(view->GetRenderText()->background_is_transparent());
    293 }
    294 
    295 // Tests if executing a command hides touch editing handles.
    296 IN_PROC_BROWSER_TEST_F(OmniboxViewViewsTest,
    297                        DeactivateTouchEditingOnExecuteCommand) {
    298   CommandLine::ForCurrentProcess()->AppendSwitch(switches::kEnableTouchEditing);
    299 
    300   OmniboxView* view = NULL;
    301   ASSERT_NO_FATAL_FAILURE(GetOmniboxViewForBrowser(browser(), &view));
    302   OmniboxViewViews* omnibox_view_views = static_cast<OmniboxViewViews*>(view);
    303   views::TextfieldTestApi textfield_test_api(omnibox_view_views);
    304 
    305   // Put a URL on the clipboard. It is written to the clipboard upon destruction
    306   // of the writer.
    307   {
    308     ui::ScopedClipboardWriter clipboard_writer(
    309         ui::CLIPBOARD_TYPE_COPY_PASTE);
    310     clipboard_writer.WriteURL(base::ASCIIToUTF16("http://www.example.com/"));
    311   }
    312 
    313   // Tap to activate touch editing.
    314   gfx::Point omnibox_center =
    315       omnibox_view_views->GetBoundsInScreen().CenterPoint();
    316   Tap(omnibox_center, omnibox_center);
    317   EXPECT_TRUE(textfield_test_api.touch_selection_controller());
    318 
    319   // Execute a command and check if it deactivate touch editing. Paste & Go is
    320   // chosen since it is specific to Omnibox and its execution wouldn't be
    321   // delgated to the base Textfield class.
    322   omnibox_view_views->ExecuteCommand(IDS_PASTE_AND_GO, ui::EF_NONE);
    323   EXPECT_FALSE(textfield_test_api.touch_selection_controller());
    324 }
    325 
    326 IN_PROC_BROWSER_TEST_F(OmniboxViewViewsTest, FocusedTextInputClient) {
    327   base::CommandLine* cmd_line = base::CommandLine::ForCurrentProcess();
    328   cmd_line->AppendSwitch(switches::kEnableTextInputFocusManager);
    329 
    330   // TODO(yukishiino): The following call to FocusLocationBar is not necessary
    331   // if the flag is enabled by default.  Remove the call once the transition to
    332   // TextInputFocusManager completes.
    333   chrome::FocusLocationBar(browser());
    334   OmniboxView* view = NULL;
    335   ASSERT_NO_FATAL_FAILURE(GetOmniboxViewForBrowser(browser(), &view));
    336   OmniboxViewViews* omnibox_view_views = static_cast<OmniboxViewViews*>(view);
    337   ui::TextInputFocusManager* text_input_focus_manager =
    338       ui::TextInputFocusManager::GetInstance();
    339   EXPECT_EQ(omnibox_view_views->GetTextInputClient(),
    340             text_input_focus_manager->GetFocusedTextInputClient());
    341 }
    342