• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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.
ChromeInForeground()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:
BrowserFocusTest()126   BrowserFocusTest() {
127     set_show_window(true);
128     EnableDOMAutomation();
129   }
130 
IsViewFocused(ViewID vid)131   bool IsViewFocused(ViewID vid) {
132     return ui_test_utils::IsViewFocused(browser(), vid);
133   }
134 
ClickOnView(ViewID vid)135   void ClickOnView(ViewID vid) {
136     ui_test_utils::ClickOnView(browser(), vid);
137   }
138 };
139 
140 class TestInterstitialPage : public InterstitialPage {
141  public:
TestInterstitialPage(TabContents * tab,bool new_navigation,const GURL & url)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 
GetHTMLContents()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.
render_view_host()159   virtual RenderViewHost* render_view_host() {
160     return InterstitialPage::render_view_host();
161   }
162 
tab()163   virtual TabContents* tab() {
164     return InterstitialPage::tab();
165   }
166 
HasFocus()167   bool HasFocus() {
168     return render_view_host()->view()->HasFocus();
169   }
170 
171  protected:
FocusedNodeChanged(bool is_editable_node)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 
IN_PROC_BROWSER_TEST_F(BrowserFocusTest,ClickingMovesFocus)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.
IN_PROC_BROWSER_TEST_F(BrowserFocusTest,FLAKY_BrowsersRememberFocus)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.
IN_PROC_BROWSER_TEST_F(BrowserFocusTest,DISABLED_TabsRememberFocus)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.
IN_PROC_BROWSER_TEST_F(BrowserFocusTest,MAYBE_TabsRememberFocusFindInPage)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.
IN_PROC_BROWSER_TEST_F(BrowserFocusTest,FLAKY_BackgroundBrowserDontStealFocus)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.
IN_PROC_BROWSER_TEST_F(BrowserFocusTest,LocationBarLockFocus)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()).
IN_PROC_BROWSER_TEST_F(BrowserFocusTest,MAYBE_FocusTraversal)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.
IN_PROC_BROWSER_TEST_F(BrowserFocusTest,MAYBE_FocusTraversalOnInterstitial)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.
IN_PROC_BROWSER_TEST_F(BrowserFocusTest,InterstitialFocus)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.
IN_PROC_BROWSER_TEST_F(BrowserFocusTest,FindFocusTest)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.
IN_PROC_BROWSER_TEST_F(BrowserFocusTest,FLAKY_TabInitialFocus)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.
IN_PROC_BROWSER_TEST_F(BrowserFocusTest,FocusOnReload)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.
IN_PROC_BROWSER_TEST_F(BrowserFocusTest,DISABLED_FocusOnReloadCrashedTab)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