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/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