Home | History | Annotate | Download | only in ui
      1 // Copyright (c) 2012 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 "base/bind.h"
      6 #include "base/file_util.h"
      7 #include "base/format_macros.h"
      8 #include "base/message_loop/message_loop.h"
      9 #include "base/path_service.h"
     10 #include "base/strings/string_number_conversions.h"
     11 #include "base/strings/stringprintf.h"
     12 #include "base/strings/utf_string_conversions.h"
     13 #include "chrome/browser/chrome_notification_types.h"
     14 #include "chrome/browser/ui/browser.h"
     15 #include "chrome/browser/ui/browser_commands.h"
     16 #include "chrome/browser/ui/browser_tabstrip.h"
     17 #include "chrome/browser/ui/browser_window.h"
     18 #include "chrome/browser/ui/chrome_pages.h"
     19 #include "chrome/browser/ui/omnibox/location_bar.h"
     20 #include "chrome/browser/ui/omnibox/omnibox_edit_controller.h"
     21 #include "chrome/browser/ui/omnibox/omnibox_edit_model.h"
     22 #include "chrome/browser/ui/omnibox/omnibox_view.h"
     23 #include "chrome/browser/ui/tabs/tab_strip_model.h"
     24 #include "chrome/browser/ui/view_ids.h"
     25 #include "chrome/common/chrome_paths.h"
     26 #include "chrome/common/url_constants.h"
     27 #include "chrome/test/base/in_process_browser_test.h"
     28 #include "chrome/test/base/interactive_test_utils.h"
     29 #include "chrome/test/base/ui_test_utils.h"
     30 #include "content/public/browser/interstitial_page.h"
     31 #include "content/public/browser/interstitial_page_delegate.h"
     32 #include "content/public/browser/notification_service.h"
     33 #include "content/public/browser/render_view_host.h"
     34 #include "content/public/browser/render_widget_host_view.h"
     35 #include "content/public/browser/web_contents.h"
     36 #include "content/public/browser/web_contents_view.h"
     37 #include "content/public/test/browser_test_utils.h"
     38 #include "net/test/embedded_test_server/embedded_test_server.h"
     39 
     40 #if defined(OS_WIN)
     41 #include <windows.h>
     42 #include <Psapi.h>
     43 #include "base/strings/string_util.h"
     44 #endif
     45 
     46 using content::InterstitialPage;
     47 using content::NavigationController;
     48 using content::RenderViewHost;
     49 using content::WebContents;
     50 
     51 #if defined(OS_MACOSX)
     52 // TODO(suzhe): http://crbug.com/60973
     53 #define MAYBE_FocusTraversal DISABLED_FocusTraversal
     54 #define MAYBE_FocusTraversalOnInterstitial DISABLED_FocusTraversalOnInterstitial
     55 #elif defined(OS_WIN) || defined(OS_CHROMEOS)
     56 // http://crbug.com/109770 and http://crbug.com/62544
     57 #define MAYBE_FocusTraversal FocusTraversal
     58 #define MAYBE_FocusTraversalOnInterstitial DISABLED_FocusTraversalOnInterstitial
     59 #else
     60 #define MAYBE_FocusTraversal FocusTraversal
     61 #define MAYBE_FocusTraversalOnInterstitial FocusTraversalOnInterstitial
     62 #endif
     63 
     64 #if defined(OS_LINUX) || defined(OS_MACOSX)
     65 // TODO(jcampan): http://crbug.com/23683 for linux.
     66 // TODO(suzhe): http://crbug.com/49737 for mac.
     67 #define MAYBE_TabsRememberFocusFindInPage DISABLED_TabsRememberFocusFindInPage
     68 #elif defined(OS_WIN)
     69 // Flaky, http://crbug.com/62537.
     70 #define MAYBE_TabsRememberFocusFindInPage DISABLED_TabsRememberFocusFindInPage
     71 #endif
     72 
     73 namespace {
     74 
     75 // The delay waited in some cases where we don't have a notifications for an
     76 // action we take.
     77 const int kActionDelayMs = 500;
     78 
     79 // Maxiumum time to wait until the focus is moved to expected view.
     80 const int kFocusChangeTimeoutMs = 500;
     81 
     82 const char kSimplePage[] = "/focus/page_with_focus.html";
     83 const char kStealFocusPage[] = "/focus/page_steals_focus.html";
     84 const char kTypicalPage[] = "/focus/typical_page.html";
     85 const char kTypicalPageName[] = "typical_page.html";
     86 
     87 // Test to make sure Chrome is in the foreground as we start testing. This is
     88 // required for tests that synthesize input to the Chrome window.
     89 bool ChromeInForeground() {
     90 #if defined(OS_WIN)
     91   HWND window = ::GetForegroundWindow();
     92   std::wstring caption;
     93   std::wstring filename;
     94   int len = ::GetWindowTextLength(window) + 1;
     95   if (len > 1)
     96     ::GetWindowText(window, WriteInto(&caption, len), len);
     97   bool chrome_window_in_foreground =
     98       EndsWith(caption, L" - Google Chrome", true) ||
     99       EndsWith(caption, L" - Chromium", true);
    100   if (!chrome_window_in_foreground) {
    101     DWORD process_id;
    102     int thread_id = ::GetWindowThreadProcessId(window, &process_id);
    103 
    104     base::ProcessHandle process;
    105     if (base::OpenProcessHandleWithAccess(process_id,
    106                                           PROCESS_QUERY_LIMITED_INFORMATION,
    107                                           &process)) {
    108       if (!GetProcessImageFileName(process, WriteInto(&filename, MAX_PATH),
    109                                    MAX_PATH)) {
    110         int error = GetLastError();
    111         filename = std::wstring(L"Unable to read filename for process id '" +
    112                                 base::IntToString16(process_id) +
    113                                 L"' (error ") +
    114                                 base::IntToString16(error) + L")";
    115       }
    116       base::CloseProcessHandle(process);
    117     }
    118   }
    119   EXPECT_TRUE(chrome_window_in_foreground)
    120       << "Chrome must be in the foreground when running interactive tests\n"
    121       << "Process in foreground: " << filename.c_str() << "\n"
    122       << "Window: " << window << "\n"
    123       << "Caption: " << caption.c_str();
    124   return chrome_window_in_foreground;
    125 #else
    126   // Windows only at the moment.
    127   return true;
    128 #endif
    129 }
    130 
    131 // Wait the focus change in message loop.
    132 void CheckFocus(Browser* browser, ViewID id, const base::Time& timeout) {
    133   if (ui_test_utils::IsViewFocused(browser, id) ||
    134       base::Time::Now() > timeout) {
    135     base::MessageLoop::current()->PostTask(FROM_HERE,
    136                                            base::MessageLoop::QuitClosure());
    137   } else {
    138     base::MessageLoop::current()->PostDelayedTask(
    139         FROM_HERE,
    140         base::Bind(&CheckFocus, browser, id, timeout),
    141         base::TimeDelta::FromMilliseconds(10));
    142   }
    143 };
    144 
    145 class BrowserFocusTest : public InProcessBrowserTest {
    146  public:
    147   bool IsViewFocused(ViewID vid) {
    148     return ui_test_utils::IsViewFocused(browser(), vid);
    149   }
    150 
    151   void ClickOnView(ViewID vid) {
    152     ui_test_utils::ClickOnView(browser(), vid);
    153   }
    154 
    155   bool WaitForFocusChange(ViewID vid) {
    156     const base::Time timeout = base::Time::Now() +
    157         base::TimeDelta::FromMilliseconds(kFocusChangeTimeoutMs);
    158     base::MessageLoop::current()->PostDelayedTask(
    159         FROM_HERE,
    160         base::Bind(&CheckFocus, browser(), vid, timeout),
    161         base::TimeDelta::FromMilliseconds(100));
    162     content::RunMessageLoop();
    163     return IsViewFocused(vid);
    164   }
    165 };
    166 
    167 class TestInterstitialPage : public content::InterstitialPageDelegate {
    168  public:
    169   TestInterstitialPage(WebContents* tab, bool new_navigation, const GURL& url) {
    170     base::FilePath file_path;
    171     bool r = PathService::Get(chrome::DIR_TEST_DATA, &file_path);
    172     EXPECT_TRUE(r);
    173     file_path = file_path.AppendASCII("focus");
    174     file_path = file_path.AppendASCII(kTypicalPageName);
    175     r = file_util::ReadFileToString(file_path, &html_contents_);
    176     EXPECT_TRUE(r);
    177     interstitial_page_ = InterstitialPage::Create(
    178         tab, new_navigation, url , this);
    179     interstitial_page_->Show();
    180   }
    181 
    182   virtual std::string GetHTMLContents() OVERRIDE {
    183     return html_contents_;
    184   }
    185 
    186   RenderViewHost* render_view_host() {
    187     return interstitial_page_->GetRenderViewHostForTesting();
    188   }
    189 
    190   void DontProceed() {
    191     interstitial_page_->DontProceed();
    192   }
    193 
    194   bool HasFocus() {
    195     return render_view_host()->GetView()->HasFocus();
    196   }
    197 
    198  private:
    199   std::string html_contents_;
    200   InterstitialPage* interstitial_page_;  // Owns us.
    201 };
    202 
    203 // Flaky on mac. http://crbug.com/67301.
    204 #if defined(OS_MACOSX)
    205 #define MAYBE_ClickingMovesFocus DISABLED_ClickingMovesFocus
    206 #else
    207 #define MAYBE_ClickingMovesFocus ClickingMovesFocus
    208 #endif
    209 IN_PROC_BROWSER_TEST_F(BrowserFocusTest, MAYBE_ClickingMovesFocus) {
    210   ASSERT_TRUE(ui_test_utils::BringBrowserWindowToFront(browser()));
    211 #if defined(OS_POSIX)
    212   // It seems we have to wait a little bit for the widgets to spin up before
    213   // we can start clicking on them.
    214   base::MessageLoop::current()->PostDelayedTask(
    215       FROM_HERE,
    216       base::MessageLoop::QuitClosure(),
    217       base::TimeDelta::FromMilliseconds(kActionDelayMs));
    218   content::RunMessageLoop();
    219 #endif  // defined(OS_POSIX)
    220 
    221   ASSERT_TRUE(IsViewFocused(VIEW_ID_OMNIBOX));
    222 
    223   ClickOnView(VIEW_ID_TAB_CONTAINER);
    224   ASSERT_TRUE(IsViewFocused(VIEW_ID_TAB_CONTAINER));
    225 
    226   ClickOnView(VIEW_ID_OMNIBOX);
    227   ASSERT_TRUE(IsViewFocused(VIEW_ID_OMNIBOX));
    228 }
    229 
    230 // Flaky, http://crbug.com/69034.
    231 IN_PROC_BROWSER_TEST_F(BrowserFocusTest, DISABLED_BrowsersRememberFocus) {
    232   ASSERT_TRUE(ui_test_utils::BringBrowserWindowToFront(browser()));
    233   ASSERT_TRUE(embedded_test_server()->InitializeAndWaitUntilReady());
    234 
    235   // First we navigate to our test page.
    236   GURL url = embedded_test_server()->GetURL(kSimplePage);
    237   ui_test_utils::NavigateToURL(browser(), url);
    238 
    239   gfx::NativeWindow window = browser()->window()->GetNativeWindow();
    240 
    241   // The focus should be on the Tab contents.
    242   ASSERT_TRUE(IsViewFocused(VIEW_ID_TAB_CONTAINER));
    243   // Now hide the window, show it again, the focus should not have changed.
    244   ui_test_utils::HideNativeWindow(window);
    245   ASSERT_TRUE(ui_test_utils::ShowAndFocusNativeWindow(window));
    246   ASSERT_TRUE(IsViewFocused(VIEW_ID_TAB_CONTAINER));
    247 
    248   chrome::FocusLocationBar(browser());
    249   ASSERT_TRUE(IsViewFocused(VIEW_ID_OMNIBOX));
    250   // Hide the window, show it again, the focus should not have changed.
    251   ui_test_utils::HideNativeWindow(window);
    252   ASSERT_TRUE(ui_test_utils::ShowAndFocusNativeWindow(window));
    253   ASSERT_TRUE(IsViewFocused(VIEW_ID_OMNIBOX));
    254 }
    255 
    256 // Tabs remember focus.
    257 // Disabled, http://crbug.com/62542.
    258 IN_PROC_BROWSER_TEST_F(BrowserFocusTest, DISABLED_TabsRememberFocus) {
    259   ASSERT_TRUE(ui_test_utils::BringBrowserWindowToFront(browser()));
    260   ASSERT_TRUE(embedded_test_server()->InitializeAndWaitUntilReady());
    261 
    262   // First we navigate to our test page.
    263   GURL url = embedded_test_server()->GetURL(kSimplePage);
    264   ui_test_utils::NavigateToURL(browser(), url);
    265 
    266   // Create several tabs.
    267   for (int i = 0; i < 4; ++i) {
    268     chrome::AddSelectedTabWithURL(browser(), url,
    269                                   content::PAGE_TRANSITION_TYPED);
    270   }
    271 
    272   // Alternate focus for the tab.
    273   const bool kFocusPage[3][5] = {
    274     { true, true, true, true, false },
    275     { false, false, false, false, false },
    276     { false, true, false, true, false }
    277   };
    278 
    279   for (int i = 1; i < 3; i++) {
    280     for (int j = 0; j < 5; j++) {
    281       // Activate the tab.
    282       browser()->tab_strip_model()->ActivateTabAt(j, true);
    283 
    284       // Activate the location bar or the page.
    285       if (kFocusPage[i][j]) {
    286         browser()->tab_strip_model()->GetWebContentsAt(j)->GetView()->Focus();
    287       } else {
    288         chrome::FocusLocationBar(browser());
    289       }
    290     }
    291 
    292     // Now come back to the tab and check the right view is focused.
    293     for (int j = 0; j < 5; j++) {
    294       // Activate the tab.
    295       browser()->tab_strip_model()->ActivateTabAt(j, true);
    296 
    297       ViewID vid = kFocusPage[i][j] ? VIEW_ID_TAB_CONTAINER : VIEW_ID_OMNIBOX;
    298       ASSERT_TRUE(IsViewFocused(vid));
    299     }
    300 
    301     browser()->tab_strip_model()->ActivateTabAt(0, true);
    302     // Try the above, but with ctrl+tab. Since tab normally changes focus,
    303     // this has regressed in the past. Loop through several times to be sure.
    304     for (int j = 0; j < 15; j++) {
    305       ViewID vid = kFocusPage[i][j % 5] ? VIEW_ID_TAB_CONTAINER :
    306                                           VIEW_ID_OMNIBOX;
    307       ASSERT_TRUE(IsViewFocused(vid));
    308 
    309       ASSERT_TRUE(ui_test_utils::SendKeyPressSync(
    310           browser(), ui::VKEY_TAB, true, false, false, false));
    311     }
    312 
    313     // As above, but with ctrl+shift+tab.
    314     browser()->tab_strip_model()->ActivateTabAt(4, true);
    315     for (int j = 14; j >= 0; --j) {
    316       ViewID vid = kFocusPage[i][j % 5] ? VIEW_ID_TAB_CONTAINER :
    317                                           VIEW_ID_OMNIBOX;
    318       ASSERT_TRUE(IsViewFocused(vid));
    319 
    320       ASSERT_TRUE(ui_test_utils::SendKeyPressSync(
    321           browser(), ui::VKEY_TAB, true, true, false, false));
    322     }
    323   }
    324 }
    325 
    326 // Tabs remember focus with find-in-page box.
    327 IN_PROC_BROWSER_TEST_F(BrowserFocusTest, MAYBE_TabsRememberFocusFindInPage) {
    328   ASSERT_TRUE(ui_test_utils::BringBrowserWindowToFront(browser()));
    329   ASSERT_TRUE(embedded_test_server()->InitializeAndWaitUntilReady());
    330 
    331   // First we navigate to our test page.
    332   GURL url = embedded_test_server()->GetURL(kSimplePage);
    333   ui_test_utils::NavigateToURL(browser(), url);
    334 
    335   chrome::Find(browser());
    336   ui_test_utils::FindInPage(
    337       browser()->tab_strip_model()->GetActiveWebContents(),
    338       ASCIIToUTF16("a"), true, false, NULL, NULL);
    339   ASSERT_TRUE(IsViewFocused(VIEW_ID_FIND_IN_PAGE_TEXT_FIELD));
    340 
    341   // Focus the location bar.
    342   chrome::FocusLocationBar(browser());
    343 
    344   // Create a 2nd tab.
    345   chrome::AddSelectedTabWithURL(browser(), url, content::PAGE_TRANSITION_TYPED);
    346 
    347   // Focus should be on the recently opened tab page.
    348   ASSERT_TRUE(IsViewFocused(VIEW_ID_TAB_CONTAINER));
    349 
    350   // Select 1st tab, focus should still be on the location-bar.
    351   // (bug http://crbug.com/23296)
    352   browser()->tab_strip_model()->ActivateTabAt(0, true);
    353   ASSERT_TRUE(IsViewFocused(VIEW_ID_OMNIBOX));
    354 
    355   // Now open the find box again, switch to another tab and come back, the focus
    356   // should return to the find box.
    357   chrome::Find(browser());
    358   ASSERT_TRUE(IsViewFocused(VIEW_ID_FIND_IN_PAGE_TEXT_FIELD));
    359   browser()->tab_strip_model()->ActivateTabAt(1, true);
    360   ASSERT_TRUE(IsViewFocused(VIEW_ID_TAB_CONTAINER));
    361   browser()->tab_strip_model()->ActivateTabAt(0, true);
    362   ASSERT_TRUE(IsViewFocused(VIEW_ID_FIND_IN_PAGE_TEXT_FIELD));
    363 }
    364 
    365 // Background window does not steal focus.
    366 // Flaky, http://crbug.com/62538.
    367 IN_PROC_BROWSER_TEST_F(BrowserFocusTest,
    368                        DISABLED_BackgroundBrowserDontStealFocus) {
    369   ASSERT_TRUE(ui_test_utils::BringBrowserWindowToFront(browser()));
    370   ASSERT_TRUE(embedded_test_server()->InitializeAndWaitUntilReady());
    371 
    372   // Open a new browser window.
    373   Browser* browser2 =
    374       new Browser(Browser::CreateParams(browser()->profile(),
    375                                         browser()->host_desktop_type()));
    376   ASSERT_TRUE(browser2);
    377   chrome::AddBlankTabAt(browser2, -1, true);
    378   browser2->window()->Show();
    379 
    380   Browser* focused_browser = NULL;
    381   Browser* unfocused_browser = NULL;
    382 #if defined(USE_X11)
    383   // On X11, calling Activate() is not guaranteed to move focus, so we have
    384   // to figure out which browser does have focus.
    385   if (browser2->window()->IsActive()) {
    386     focused_browser = browser2;
    387     unfocused_browser = browser();
    388   } else if (browser()->window()->IsActive()) {
    389     focused_browser = browser();
    390     unfocused_browser = browser2;
    391   } else {
    392     FAIL() << "Could not determine which browser has focus";
    393   }
    394 #elif defined(OS_WIN)
    395   focused_browser = browser();
    396   unfocused_browser = browser2;
    397 #elif defined(OS_MACOSX)
    398   // On Mac, the newly created window always gets the focus.
    399   focused_browser = browser2;
    400   unfocused_browser = browser();
    401 #endif
    402 
    403   GURL steal_focus_url = embedded_test_server()->GetURL(kStealFocusPage);
    404   ui_test_utils::NavigateToURL(unfocused_browser, steal_focus_url);
    405 
    406   // Activate the first browser.
    407   focused_browser->window()->Activate();
    408 
    409   ASSERT_TRUE(content::ExecuteScript(
    410       unfocused_browser->tab_strip_model()->GetActiveWebContents(),
    411       "stealFocus();"));
    412 
    413   // Make sure the first browser is still active.
    414   EXPECT_TRUE(focused_browser->window()->IsActive());
    415 }
    416 
    417 // Page cannot steal focus when focus is on location bar.
    418 IN_PROC_BROWSER_TEST_F(BrowserFocusTest, LocationBarLockFocus) {
    419   ASSERT_TRUE(ui_test_utils::BringBrowserWindowToFront(browser()));
    420   ASSERT_TRUE(embedded_test_server()->InitializeAndWaitUntilReady());
    421 
    422   // Open the page that steals focus.
    423   GURL url = embedded_test_server()->GetURL(kStealFocusPage);
    424   ui_test_utils::NavigateToURL(browser(), url);
    425 
    426   chrome::FocusLocationBar(browser());
    427 
    428   ASSERT_TRUE(content::ExecuteScript(
    429       browser()->tab_strip_model()->GetActiveWebContents(),
    430       "stealFocus();"));
    431 
    432   // Make sure the location bar is still focused.
    433   ASSERT_TRUE(IsViewFocused(VIEW_ID_OMNIBOX));
    434 }
    435 
    436 // Focus traversal on a regular page.
    437 // Note that this test relies on a notification from the renderer that the
    438 // focus has changed in the page.  The notification in the renderer may change
    439 // at which point this test would fail (see comment in
    440 // RenderWidget::didFocus()).
    441 IN_PROC_BROWSER_TEST_F(BrowserFocusTest, MAYBE_FocusTraversal) {
    442   ASSERT_TRUE(ui_test_utils::BringBrowserWindowToFront(browser()));
    443   ASSERT_TRUE(embedded_test_server()->InitializeAndWaitUntilReady());
    444 
    445   // First we navigate to our test page.
    446   GURL url = embedded_test_server()->GetURL(kTypicalPage);
    447   ui_test_utils::NavigateToURL(browser(), url);
    448 
    449   chrome::FocusLocationBar(browser());
    450 
    451   const char* kTextElementID = "textEdit";
    452   const char* kExpElementIDs[] = {
    453     "",  // Initially no element in the page should be focused
    454          // (the location bar is focused).
    455     kTextElementID, "searchButton", "luckyButton", "googleLink", "gmailLink",
    456     "gmapLink"
    457   };
    458 
    459   // Test forward focus traversal.
    460   for (int i = 0; i < 3; ++i) {
    461     SCOPED_TRACE(base::StringPrintf("outer loop: %d", i));
    462     // Location bar should be focused.
    463     ASSERT_TRUE(IsViewFocused(VIEW_ID_OMNIBOX));
    464 
    465     // Move the caret to the end, otherwise the next Tab key may not move focus.
    466     ASSERT_TRUE(ui_test_utils::SendKeyPressSync(
    467         browser(), ui::VKEY_END, false, false, false, false));
    468 
    469     // Now let's press tab to move the focus.
    470     for (size_t j = 0; j < arraysize(kExpElementIDs); ++j) {
    471       SCOPED_TRACE(base::StringPrintf("inner loop %" PRIuS, j));
    472       // Let's make sure the focus is on the expected element in the page.
    473       std::string actual;
    474       ASSERT_TRUE(content::ExecuteScriptAndExtractString(
    475           browser()->tab_strip_model()->GetActiveWebContents(),
    476           "window.domAutomationController.send(getFocusedElement());",
    477           &actual));
    478       ASSERT_STREQ(kExpElementIDs[j], actual.c_str());
    479 
    480       if (j < arraysize(kExpElementIDs) - 1) {
    481         // If the next element is the kTextElementID, we expect to be
    482         // notified we have switched to an editable node.
    483         bool is_editable_node =
    484             (strcmp(kTextElementID, kExpElementIDs[j + 1]) == 0);
    485         content::Details<bool> details(&is_editable_node);
    486 
    487         ASSERT_TRUE(ui_test_utils::SendKeyPressAndWaitWithDetails(
    488             browser(), ui::VKEY_TAB, false, false, false, false,
    489             content::NOTIFICATION_FOCUS_CHANGED_IN_PAGE,
    490             content::NotificationSource(content::Source<RenderViewHost>(
    491                 browser()->tab_strip_model()->GetActiveWebContents()->
    492                     GetRenderViewHost())),
    493             details));
    494       } else {
    495         // On the last tab key press, the focus returns to the browser.
    496         ASSERT_TRUE(ui_test_utils::SendKeyPressAndWait(
    497             browser(), ui::VKEY_TAB, false, false, false, false,
    498             chrome::NOTIFICATION_FOCUS_RETURNED_TO_BROWSER,
    499             content::NotificationSource(content::Source<Browser>(browser()))));
    500       }
    501     }
    502 
    503     // At this point the renderer has sent us a message asking to advance the
    504     // focus (as the end of the focus loop was reached in the renderer).
    505     // We need to run the message loop to process it.
    506     content::RunAllPendingInMessageLoop();
    507   }
    508 
    509   // Now let's try reverse focus traversal.
    510   for (int i = 0; i < 3; ++i) {
    511     SCOPED_TRACE(base::StringPrintf("outer loop: %d", i));
    512     // Location bar should be focused.
    513     ASSERT_TRUE(IsViewFocused(VIEW_ID_OMNIBOX));
    514 
    515     // Move the caret to the end, otherwise the next Tab key may not move focus.
    516     ASSERT_TRUE(ui_test_utils::SendKeyPressSync(
    517         browser(), ui::VKEY_END, false, false, false, false));
    518 
    519     // Now let's press shift-tab to move the focus in reverse.
    520     for (size_t j = 0; j < arraysize(kExpElementIDs); ++j) {
    521       SCOPED_TRACE(base::StringPrintf("inner loop: %" PRIuS, j));
    522       const char* next_element =
    523           kExpElementIDs[arraysize(kExpElementIDs) - 1 - j];
    524 
    525       if (j < arraysize(kExpElementIDs) - 1) {
    526         // If the next element is the kTextElementID, we expect to be
    527         // notified we have switched to an editable node.
    528         bool is_editable_node = (strcmp(kTextElementID, next_element) == 0);
    529         content::Details<bool> details(&is_editable_node);
    530 
    531         ASSERT_TRUE(ui_test_utils::SendKeyPressAndWaitWithDetails(
    532             browser(), ui::VKEY_TAB, false, true, false, false,
    533             content::NOTIFICATION_FOCUS_CHANGED_IN_PAGE,
    534             content::NotificationSource(content::Source<RenderViewHost>(
    535                 browser()->tab_strip_model()->GetActiveWebContents()->
    536                     GetRenderViewHost())),
    537             details));
    538       } else {
    539         // On the last tab key press, the focus returns to the browser.
    540         ASSERT_TRUE(ui_test_utils::SendKeyPressAndWait(
    541             browser(), ui::VKEY_TAB, false, true, false, false,
    542             chrome::NOTIFICATION_FOCUS_RETURNED_TO_BROWSER,
    543             content::NotificationSource(content::Source<Browser>(browser()))));
    544       }
    545 
    546       // Let's make sure the focus is on the expected element in the page.
    547       std::string actual;
    548       ASSERT_TRUE(content::ExecuteScriptAndExtractString(
    549           browser()->tab_strip_model()->GetActiveWebContents(),
    550           "window.domAutomationController.send(getFocusedElement());",
    551           &actual));
    552       ASSERT_STREQ(next_element, actual.c_str());
    553     }
    554 
    555     // At this point the renderer has sent us a message asking to advance the
    556     // focus (as the end of the focus loop was reached in the renderer).
    557     // We need to run the message loop to process it.
    558     content::RunAllPendingInMessageLoop();
    559   }
    560 }
    561 
    562 // Focus traversal while an interstitial is showing.
    563 IN_PROC_BROWSER_TEST_F(BrowserFocusTest, MAYBE_FocusTraversalOnInterstitial) {
    564   ASSERT_TRUE(ui_test_utils::BringBrowserWindowToFront(browser()));
    565   ASSERT_TRUE(embedded_test_server()->InitializeAndWaitUntilReady());
    566 
    567   // First we navigate to our test page.
    568   GURL url = embedded_test_server()->GetURL(kSimplePage);
    569   ui_test_utils::NavigateToURL(browser(), url);
    570 
    571   // Focus should be on the page.
    572   ASSERT_TRUE(IsViewFocused(VIEW_ID_TAB_CONTAINER));
    573 
    574   // Let's show an interstitial.
    575   TestInterstitialPage* interstitial_page = new TestInterstitialPage(
    576       browser()->tab_strip_model()->GetActiveWebContents(),
    577       true, GURL("http://interstitial.com"));
    578   // Give some time for the interstitial to show.
    579   base::MessageLoop::current()->PostDelayedTask(
    580       FROM_HERE,
    581       base::MessageLoop::QuitClosure(),
    582       base::TimeDelta::FromSeconds(1));
    583   content::RunMessageLoop();
    584 
    585   chrome::FocusLocationBar(browser());
    586 
    587   const char* kExpElementIDs[] = {
    588     "",  // Initially no element in the page should be focused
    589          // (the location bar is focused).
    590     "textEdit", "searchButton", "luckyButton", "googleLink", "gmailLink",
    591     "gmapLink"
    592   };
    593 
    594   // Test forward focus traversal.
    595   for (int i = 0; i < 2; ++i) {
    596     // Location bar should be focused.
    597     ASSERT_TRUE(IsViewFocused(VIEW_ID_OMNIBOX));
    598 
    599     // Move the caret to the end, otherwise the next Tab key may not move focus.
    600     ASSERT_TRUE(ui_test_utils::SendKeyPressSync(
    601         browser(), ui::VKEY_END, false, false, false, false));
    602 
    603     // Now let's press tab to move the focus.
    604     for (size_t j = 0; j < 7; ++j) {
    605       // Let's make sure the focus is on the expected element in the page.
    606       std::string actual;
    607       ASSERT_TRUE(content::ExecuteScriptAndExtractString(
    608           interstitial_page->render_view_host(),
    609           "window.domAutomationController.send(getFocusedElement());",
    610           &actual));
    611       ASSERT_STREQ(kExpElementIDs[j], actual.c_str());
    612 
    613       int notification_type;
    614       content::NotificationSource notification_source =
    615           content::NotificationService::AllSources();
    616       if (j < arraysize(kExpElementIDs) - 1) {
    617         notification_type = content::NOTIFICATION_FOCUS_CHANGED_IN_PAGE;
    618         notification_source = content::Source<RenderViewHost>(
    619             interstitial_page->render_view_host());
    620       } else {
    621         // On the last tab key press, the focus returns to the browser.
    622         notification_type = chrome::NOTIFICATION_FOCUS_RETURNED_TO_BROWSER;
    623         notification_source = content::Source<Browser>(browser());
    624       }
    625 
    626       ASSERT_TRUE(ui_test_utils::SendKeyPressAndWait(
    627           browser(), ui::VKEY_TAB, false, false, false, false,
    628           notification_type, notification_source));
    629     }
    630 
    631     // At this point the renderer has sent us a message asking to advance the
    632     // focus (as the end of the focus loop was reached in the renderer).
    633     // We need to run the message loop to process it.
    634     content::RunAllPendingInMessageLoop();
    635   }
    636 
    637   // Now let's try reverse focus traversal.
    638   for (int i = 0; i < 2; ++i) {
    639     // Location bar should be focused.
    640     ASSERT_TRUE(IsViewFocused(VIEW_ID_OMNIBOX));
    641 
    642     // Move the caret to the end, otherwise the next Tab key may not move focus.
    643     ASSERT_TRUE(ui_test_utils::SendKeyPressSync(
    644         browser(), ui::VKEY_END, false, false, false, false));
    645 
    646     // Now let's press shift-tab to move the focus in reverse.
    647     for (size_t j = 0; j < 7; ++j) {
    648       int notification_type;
    649       content::NotificationSource notification_source =
    650           content::NotificationService::AllSources();
    651       if (j < arraysize(kExpElementIDs) - 1) {
    652         notification_type = content::NOTIFICATION_FOCUS_CHANGED_IN_PAGE;
    653         notification_source = content::Source<RenderViewHost>(
    654             interstitial_page->render_view_host());
    655       } else {
    656         // On the last tab key press, the focus returns to the browser.
    657         notification_type = chrome::NOTIFICATION_FOCUS_RETURNED_TO_BROWSER;
    658         notification_source = content::Source<Browser>(browser());
    659       }
    660 
    661       ASSERT_TRUE(ui_test_utils::SendKeyPressAndWait(
    662           browser(), ui::VKEY_TAB, false, true, false, false,
    663           notification_type, notification_source));
    664 
    665       // Let's make sure the focus is on the expected element in the page.
    666       std::string actual;
    667       ASSERT_TRUE(content::ExecuteScriptAndExtractString(
    668           interstitial_page->render_view_host(),
    669           "window.domAutomationController.send(getFocusedElement());",
    670           &actual));
    671       ASSERT_STREQ(kExpElementIDs[6 - j], actual.c_str());
    672     }
    673 
    674     // At this point the renderer has sent us a message asking to advance the
    675     // focus (as the end of the focus loop was reached in the renderer).
    676     // We need to run the message loop to process it.
    677     content::RunAllPendingInMessageLoop();
    678   }
    679 }
    680 
    681 // Focus stays on page with interstitials.
    682 // http://crbug.com/81451
    683 IN_PROC_BROWSER_TEST_F(BrowserFocusTest, DISABLED_InterstitialFocus) {
    684   ASSERT_TRUE(ui_test_utils::BringBrowserWindowToFront(browser()));
    685   ASSERT_TRUE(embedded_test_server()->InitializeAndWaitUntilReady());
    686 
    687   // First we navigate to our test page.
    688   GURL url = embedded_test_server()->GetURL(kSimplePage);
    689   ui_test_utils::NavigateToURL(browser(), url);
    690 
    691   // Page should have focus.
    692   ASSERT_TRUE(IsViewFocused(VIEW_ID_TAB_CONTAINER));
    693   EXPECT_TRUE(browser()->tab_strip_model()->GetActiveWebContents()->
    694                   GetRenderViewHost()->GetView()->HasFocus());
    695 
    696   // Let's show an interstitial.
    697   TestInterstitialPage* interstitial_page = new TestInterstitialPage(
    698       browser()->tab_strip_model()->GetActiveWebContents(),
    699       true, GURL("http://interstitial.com"));
    700   // Give some time for the interstitial to show.
    701   base::MessageLoop::current()->PostDelayedTask(
    702       FROM_HERE,
    703       base::MessageLoop::QuitClosure(),
    704       base::TimeDelta::FromSeconds(1));
    705   content::RunMessageLoop();
    706 
    707   // The interstitial should have focus now.
    708   ASSERT_TRUE(IsViewFocused(VIEW_ID_TAB_CONTAINER));
    709   EXPECT_TRUE(interstitial_page->HasFocus());
    710 
    711   // Hide the interstitial.
    712   interstitial_page->DontProceed();
    713 
    714   // Focus should be back on the original page.
    715   ASSERT_TRUE(IsViewFocused(VIEW_ID_TAB_CONTAINER));
    716 }
    717 
    718 // Make sure Find box can request focus, even when it is already open.
    719 // Disabled due to flakiness. http://crbug.com/67301.
    720 IN_PROC_BROWSER_TEST_F(BrowserFocusTest, DISABLED_FindFocusTest) {
    721   ASSERT_TRUE(ui_test_utils::BringBrowserWindowToFront(browser()));
    722   ASSERT_TRUE(embedded_test_server()->InitializeAndWaitUntilReady());
    723 
    724   // Open some page (any page that doesn't steal focus).
    725   GURL url = embedded_test_server()->GetURL(kTypicalPage);
    726   ui_test_utils::NavigateToURL(browser(), url);
    727 
    728   EXPECT_TRUE(ChromeInForeground());
    729 
    730 #if defined(OS_MACOSX)
    731   // Press Cmd+F, which will make the Find box open and request focus.
    732   ASSERT_TRUE(ui_test_utils::SendKeyPressSync(
    733       browser(), ui::VKEY_F, false, false, false, true));
    734 #else
    735   // Press Ctrl+F, which will make the Find box open and request focus.
    736   ASSERT_TRUE(ui_test_utils::SendKeyPressSync(
    737       browser(), ui::VKEY_F, true, false, false, false));
    738 #endif
    739 
    740   ASSERT_TRUE(WaitForFocusChange(VIEW_ID_FIND_IN_PAGE_TEXT_FIELD));
    741 
    742   chrome::FocusLocationBar(browser());
    743   ASSERT_TRUE(IsViewFocused(VIEW_ID_OMNIBOX));
    744 
    745   // Now press Ctrl+F again and focus should move to the Find box.
    746 #if defined(OS_MACOSX)
    747   ASSERT_TRUE(ui_test_utils::SendKeyPressSync(
    748       browser(), ui::VKEY_F, false, false, false, true));
    749 #else
    750   ASSERT_TRUE(ui_test_utils::SendKeyPressSync(
    751       browser(), ui::VKEY_F, true, false, false, false));
    752 #endif
    753   ASSERT_TRUE(IsViewFocused(VIEW_ID_FIND_IN_PAGE_TEXT_FIELD));
    754 
    755   // Set focus to the page.
    756   ClickOnView(VIEW_ID_TAB_CONTAINER);
    757   ASSERT_TRUE(IsViewFocused(VIEW_ID_TAB_CONTAINER));
    758 
    759   // Now press Ctrl+F again and focus should move to the Find box.
    760 #if defined(OS_MACOSX)
    761   ASSERT_TRUE(ui_test_utils::SendKeyPressSync(
    762       browser(), ui::VKEY_F, false, false, false, true));
    763 #else
    764   ASSERT_TRUE(ui_test_utils::SendKeyPressSync(
    765       browser(), ui::VKEY_F, true, false, false, false));
    766 #endif
    767 
    768   ASSERT_TRUE(WaitForFocusChange(VIEW_ID_FIND_IN_PAGE_TEXT_FIELD));
    769 }
    770 
    771 // Makes sure the focus is in the right location when opening the different
    772 // types of tabs.
    773 // Flaky, http://crbug.com/62539.
    774 IN_PROC_BROWSER_TEST_F(BrowserFocusTest, DISABLED_TabInitialFocus) {
    775   ASSERT_TRUE(ui_test_utils::BringBrowserWindowToFront(browser()));
    776 
    777   // Open the history tab, focus should be on the tab contents.
    778   chrome::ShowHistory(browser());
    779   ASSERT_NO_FATAL_FAILURE(content::WaitForLoadStop(
    780       browser()->tab_strip_model()->GetActiveWebContents()));
    781   EXPECT_TRUE(IsViewFocused(VIEW_ID_TAB_CONTAINER));
    782 
    783   // Open the new tab, focus should be on the location bar.
    784   chrome::NewTab(browser());
    785   ASSERT_NO_FATAL_FAILURE(content::WaitForLoadStop(
    786       browser()->tab_strip_model()->GetActiveWebContents()));
    787   EXPECT_TRUE(IsViewFocused(VIEW_ID_OMNIBOX));
    788 
    789   // Open the download tab, focus should be on the tab contents.
    790   chrome::ShowDownloads(browser());
    791   ASSERT_NO_FATAL_FAILURE(content::WaitForLoadStop(
    792       browser()->tab_strip_model()->GetActiveWebContents()));
    793   EXPECT_TRUE(IsViewFocused(VIEW_ID_TAB_CONTAINER));
    794 
    795   // Open about:blank, focus should be on the location bar.
    796   chrome::AddSelectedTabWithURL(browser(), GURL(content::kAboutBlankURL),
    797                                 content::PAGE_TRANSITION_LINK);
    798   ASSERT_NO_FATAL_FAILURE(content::WaitForLoadStop(
    799       browser()->tab_strip_model()->GetActiveWebContents()));
    800   EXPECT_TRUE(IsViewFocused(VIEW_ID_OMNIBOX));
    801 }
    802 
    803 // Tests that focus goes where expected when using reload.
    804 IN_PROC_BROWSER_TEST_F(BrowserFocusTest, FocusOnReload) {
    805   ASSERT_TRUE(ui_test_utils::BringBrowserWindowToFront(browser()));
    806   ASSERT_TRUE(embedded_test_server()->InitializeAndWaitUntilReady());
    807 
    808   // Open the new tab, reload.
    809   {
    810     content::WindowedNotificationObserver observer(
    811         content::NOTIFICATION_LOAD_STOP,
    812         content::NotificationService::AllSources());
    813     chrome::NewTab(browser());
    814     observer.Wait();
    815   }
    816   content::RunAllPendingInMessageLoop();
    817 
    818   {
    819     content::WindowedNotificationObserver observer(
    820         content::NOTIFICATION_LOAD_STOP,
    821         content::Source<NavigationController>(
    822             &browser()->tab_strip_model()->GetActiveWebContents()->
    823                 GetController()));
    824     chrome::Reload(browser(), CURRENT_TAB);
    825     observer.Wait();
    826   }
    827   // Focus should stay on the location bar.
    828   ASSERT_TRUE(IsViewFocused(VIEW_ID_OMNIBOX));
    829 
    830   // Open a regular page, focus the location bar, reload.
    831   ui_test_utils::NavigateToURL(browser(),
    832                                embedded_test_server()->GetURL(kSimplePage));
    833   chrome::FocusLocationBar(browser());
    834   ASSERT_TRUE(IsViewFocused(VIEW_ID_OMNIBOX));
    835   {
    836     content::WindowedNotificationObserver observer(
    837         content::NOTIFICATION_LOAD_STOP,
    838         content::Source<NavigationController>(
    839             &browser()->tab_strip_model()->GetActiveWebContents()->
    840                 GetController()));
    841     chrome::Reload(browser(), CURRENT_TAB);
    842     observer.Wait();
    843   }
    844 
    845   // Focus should now be on the tab contents.
    846   chrome::ShowDownloads(browser());
    847   ASSERT_TRUE(IsViewFocused(VIEW_ID_TAB_CONTAINER));
    848 }
    849 
    850 // Tests that focus goes where expected when using reload on a crashed tab.
    851 IN_PROC_BROWSER_TEST_F(BrowserFocusTest, DISABLED_FocusOnReloadCrashedTab) {
    852   ASSERT_TRUE(ui_test_utils::BringBrowserWindowToFront(browser()));
    853   ASSERT_TRUE(embedded_test_server()->InitializeAndWaitUntilReady());
    854 
    855   // Open a regular page, crash, reload.
    856   ui_test_utils::NavigateToURL(browser(),
    857                                embedded_test_server()->GetURL(kSimplePage));
    858   content::CrashTab(browser()->tab_strip_model()->GetActiveWebContents());
    859   {
    860     content::WindowedNotificationObserver observer(
    861         content::NOTIFICATION_LOAD_STOP,
    862         content::Source<NavigationController>(
    863             &browser()->tab_strip_model()->GetActiveWebContents()->
    864                 GetController()));
    865     chrome::Reload(browser(), CURRENT_TAB);
    866     observer.Wait();
    867   }
    868 
    869   // Focus should now be on the tab contents.
    870   chrome::ShowDownloads(browser());
    871   ASSERT_TRUE(IsViewFocused(VIEW_ID_TAB_CONTAINER));
    872 }
    873 
    874 // Tests that when a new tab is opened from the omnibox, the focus is moved from
    875 // the omnibox for the current tab.
    876 IN_PROC_BROWSER_TEST_F(BrowserFocusTest,
    877                        NavigateFromOmniboxIntoNewTab) {
    878   GURL url("http://www.google.com/");
    879   GURL url2("http://maps.google.com/");
    880 
    881   // Navigate to url.
    882   chrome::NavigateParams p(browser(), url, content::PAGE_TRANSITION_LINK);
    883   p.window_action = chrome::NavigateParams::SHOW_WINDOW;
    884   p.disposition = CURRENT_TAB;
    885   chrome::Navigate(&p);
    886 
    887   // Focus the omnibox.
    888   chrome::FocusLocationBar(browser());
    889 
    890   OmniboxEditController* controller =
    891       browser()->window()->GetLocationBar()->GetLocationEntry()->model()->
    892           controller();
    893 
    894   // Simulate an alt-enter.
    895   controller->OnAutocompleteAccept(url2, NEW_FOREGROUND_TAB,
    896                                    content::PAGE_TRANSITION_TYPED, GURL());
    897 
    898   // Make sure the second tab is selected.
    899   EXPECT_EQ(1, browser()->tab_strip_model()->active_index());
    900 
    901   // The tab contents should have the focus in the second tab.
    902   EXPECT_TRUE(ui_test_utils::IsViewFocused(browser(), VIEW_ID_TAB_CONTAINER));
    903 
    904   // Go back to the first tab. The focus should not be in the omnibox.
    905   chrome::SelectPreviousTab(browser());
    906   EXPECT_EQ(0, browser()->tab_strip_model()->active_index());
    907   EXPECT_FALSE(ui_test_utils::IsViewFocused(browser(), VIEW_ID_OMNIBOX));
    908 }
    909 
    910 IN_PROC_BROWSER_TEST_F(BrowserFocusTest, FocusOnNavigate) {
    911   // Needed on Mac.
    912   ASSERT_TRUE(ui_test_utils::BringBrowserWindowToFront(browser()));
    913   // Load the NTP.
    914   ui_test_utils::NavigateToURL(browser(), GURL(chrome::kChromeUINewTabURL));
    915   EXPECT_TRUE(IsViewFocused(VIEW_ID_OMNIBOX));
    916 
    917   // Navigate to another page.
    918   const base::FilePath::CharType* kEmptyFile = FILE_PATH_LITERAL("empty.html");
    919   GURL file_url(ui_test_utils::GetTestUrl(base::FilePath(
    920       base::FilePath::kCurrentDirectory), base::FilePath(kEmptyFile)));
    921   ui_test_utils::NavigateToURL(browser(), file_url);
    922 
    923   ClickOnView(VIEW_ID_TAB_CONTAINER);
    924 
    925   // Navigate back.  Should focus the location bar.
    926   {
    927     content::WindowedNotificationObserver back_nav_observer(
    928         content::NOTIFICATION_NAV_ENTRY_COMMITTED,
    929         content::NotificationService::AllSources());
    930     chrome::GoBack(browser(), CURRENT_TAB);
    931     back_nav_observer.Wait();
    932   }
    933 
    934   EXPECT_TRUE(IsViewFocused(VIEW_ID_OMNIBOX));
    935 
    936   // Navigate forward.  Shouldn't focus the location bar.
    937   ClickOnView(VIEW_ID_TAB_CONTAINER);
    938   {
    939     content::WindowedNotificationObserver forward_nav_observer(
    940         content::NOTIFICATION_NAV_ENTRY_COMMITTED,
    941         content::NotificationService::AllSources());
    942     chrome::GoForward(browser(), CURRENT_TAB);
    943     forward_nav_observer.Wait();
    944   }
    945 
    946   EXPECT_FALSE(IsViewFocused(VIEW_ID_OMNIBOX));
    947 }
    948 
    949 }  // namespace
    950