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