| // Copyright (c) 2009 The Chromium Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #include "base/message_loop.h" |
| #include "base/ref_counted.h" |
| #include "chrome/browser/automation/ui_controls.h" |
| #include "chrome/browser/browser.h" |
| #include "chrome/browser/view_ids.h" |
| #include "chrome/browser/views/frame/browser_view.h" |
| #include "chrome/browser/views/location_bar_view.h" |
| #include "chrome/views/focus/focus_manager.h" |
| #include "chrome/views/view.h" |
| #include "chrome/views/window/window.h" |
| #include "chrome/test/in_process_browser_test.h" |
| #include "chrome/test/ui_test_utils.h" |
| |
| namespace { |
| |
| // The delay waited in some cases where we don't have a notifications for an |
| // action we take. |
| const int kActionDelayMs = 500; |
| |
| const wchar_t kSimplePage[] = L"files/focus/page_with_focus.html"; |
| const wchar_t kStealFocusPage[] = L"files/focus/page_steals_focus.html"; |
| const wchar_t kTypicalPage[] = L"files/focus/typical_page.html"; |
| |
| class BrowserFocusTest : public InProcessBrowserTest { |
| public: |
| BrowserFocusTest() { |
| set_show_window(true); |
| EnableDOMAutomation(); |
| } |
| }; |
| |
| } // namespace |
| |
| IN_PROC_BROWSER_TEST_F(BrowserFocusTest, DISABLED_BrowsersRememberFocus) { |
| HTTPTestServer* server = StartHTTPServer(); |
| |
| // First we navigate to our test page. |
| GURL url = server->TestServerPageW(kSimplePage); |
| ui_test_utils::NavigateToURL(browser(), url); |
| |
| // The focus should be on the Tab contents. |
| HWND hwnd = reinterpret_cast<HWND>(browser()->window()->GetNativeHandle()); |
| BrowserView* browser_view = BrowserView::GetBrowserViewForHWND(hwnd); |
| ASSERT_TRUE(browser_view); |
| views::FocusManager* focus_manager = |
| views::FocusManager::GetFocusManager(hwnd); |
| ASSERT_TRUE(focus_manager); |
| |
| EXPECT_EQ(browser_view->GetContentsView(), focus_manager->GetFocusedView()); |
| |
| // Now hide the window, show it again, the focus should not have changed. |
| // TODO(jcampan): retrieve the WidgetWin and show/hide on it instead of |
| // using Windows API. |
| ::ShowWindow(hwnd, SW_HIDE); |
| ::ShowWindow(hwnd, SW_SHOW); |
| EXPECT_EQ(browser_view->GetContentsView(), focus_manager->GetFocusedView()); |
| |
| // Click on the location bar. |
| LocationBarView* location_bar = browser_view->GetLocationBarView(); |
| ui_controls::MoveMouseToCenterAndPress(location_bar, |
| ui_controls::LEFT, |
| ui_controls::DOWN | ui_controls::UP, |
| new MessageLoop::QuitTask()); |
| ui_test_utils::RunMessageLoop(); |
| // Location bar should have focus. |
| EXPECT_EQ(location_bar, focus_manager->GetFocusedView()); |
| |
| // Hide the window, show it again, the focus should not have changed. |
| ::ShowWindow(hwnd, SW_HIDE); |
| ::ShowWindow(hwnd, SW_SHOW); |
| EXPECT_EQ(location_bar, focus_manager->GetFocusedView()); |
| |
| // Open a new browser window. |
| Browser* browser2 = Browser::Create(browser()->profile()); |
| ASSERT_TRUE(browser2); |
| browser2->tabstrip_model()->delegate()->AddBlankTab(true); |
| browser2->window()->Show(); |
| ui_test_utils::NavigateToURL(browser2, url); |
| |
| HWND hwnd2 = reinterpret_cast<HWND>(browser2->window()->GetNativeHandle()); |
| BrowserView* browser_view2 = BrowserView::GetBrowserViewForHWND(hwnd2); |
| ASSERT_TRUE(browser_view2); |
| views::FocusManager* focus_manager2 = |
| views::FocusManager::GetFocusManager(hwnd2); |
| ASSERT_TRUE(focus_manager2); |
| EXPECT_EQ(browser_view2->GetContentsView(), focus_manager2->GetFocusedView()); |
| |
| // Switch to the 1st browser window, focus should still be on the location |
| // bar and the second browser should have nothing focused. |
| browser()->window()->Activate(); |
| EXPECT_EQ(location_bar, focus_manager->GetFocusedView()); |
| EXPECT_EQ(NULL, focus_manager2->GetFocusedView()); |
| |
| // Switch back to the second browser, focus should still be on the page. |
| browser2->window()->Activate(); |
| EXPECT_EQ(NULL, focus_manager->GetFocusedView()); |
| EXPECT_EQ(browser_view2->GetContentsView(), focus_manager2->GetFocusedView()); |
| |
| // Close the 2nd browser to avoid a DCHECK(). |
| browser_view2->Close(); |
| } |
| |
| // Tabs remember focus. |
| IN_PROC_BROWSER_TEST_F(BrowserFocusTest, TabsRememberFocus) { |
| HTTPTestServer* server = StartHTTPServer(); |
| |
| // First we navigate to our test page. |
| GURL url = server->TestServerPageW(kSimplePage); |
| ui_test_utils::NavigateToURL(browser(), url); |
| |
| HWND hwnd = reinterpret_cast<HWND>(browser()->window()->GetNativeHandle()); |
| BrowserView* browser_view = BrowserView::GetBrowserViewForHWND(hwnd); |
| ASSERT_TRUE(browser_view); |
| |
| views::FocusManager* focus_manager = |
| views::FocusManager::GetFocusManager(hwnd); |
| ASSERT_TRUE(focus_manager); |
| |
| // Create several tabs. |
| for (int i = 0; i < 4; ++i) { |
| browser()->AddTabWithURL(url, GURL(), PageTransition::TYPED, true, -1, |
| NULL); |
| } |
| |
| // Alternate focus for the tab. |
| const bool kFocusPage[3][5] = { |
| { true, true, true, true, false }, |
| { false, false, false, false, false }, |
| { false, true, false, true, false } |
| }; |
| |
| for (int i = 1; i < 3; i++) { |
| for (int j = 0; j < 5; j++) { |
| // Activate the tab. |
| browser()->SelectTabContentsAt(j, true); |
| |
| // Activate the location bar or the page. |
| views::View* view_to_focus = kFocusPage[i][j] ? |
| browser_view->GetContentsView() : |
| browser_view->GetLocationBarView(); |
| |
| ui_controls::MoveMouseToCenterAndPress(view_to_focus, |
| ui_controls::LEFT, |
| ui_controls::DOWN | |
| ui_controls::UP, |
| new MessageLoop::QuitTask()); |
| ui_test_utils::RunMessageLoop(); |
| } |
| |
| // Now come back to the tab and check the right view is focused. |
| for (int j = 0; j < 5; j++) { |
| // Activate the tab. |
| browser()->SelectTabContentsAt(j, true); |
| |
| // Activate the location bar or the page. |
| views::View* view = kFocusPage[i][j] ? |
| browser_view->GetContentsView() : |
| browser_view->GetLocationBarView(); |
| EXPECT_EQ(view, focus_manager->GetFocusedView()); |
| } |
| } |
| } |
| |
| // Background window does not steal focus. |
| IN_PROC_BROWSER_TEST_F(BrowserFocusTest, BackgroundBrowserDontStealFocus) { |
| HTTPTestServer* server = StartHTTPServer(); |
| |
| // First we navigate to our test page. |
| GURL url = server->TestServerPageW(kSimplePage); |
| ui_test_utils::NavigateToURL(browser(), url); |
| |
| // Open a new browser window. |
| Browser* browser2 = Browser::Create(browser()->profile()); |
| ASSERT_TRUE(browser2); |
| browser2->tabstrip_model()->delegate()->AddBlankTab(true); |
| browser2->window()->Show(); |
| GURL steal_focus_url = server->TestServerPageW(kStealFocusPage); |
| ui_test_utils::NavigateToURL(browser2, steal_focus_url); |
| |
| // Activate the first browser. |
| browser()->window()->Activate(); |
| |
| // Wait for the focus to be stolen by the other browser. |
| ::Sleep(2000); |
| |
| // Make sure the first browser is still active. |
| HWND hwnd = reinterpret_cast<HWND>(browser()->window()->GetNativeHandle()); |
| BrowserView* browser_view = BrowserView::GetBrowserViewForHWND(hwnd); |
| ASSERT_TRUE(browser_view); |
| EXPECT_TRUE(browser_view->frame()->IsActive()); |
| |
| // Close the 2nd browser to avoid a DCHECK(). |
| HWND hwnd2 = reinterpret_cast<HWND>(browser2->window()->GetNativeHandle()); |
| BrowserView* browser_view2 = BrowserView::GetBrowserViewForHWND(hwnd2); |
| browser_view2->Close(); |
| } |
| |
| // Page cannot steal focus when focus is on location bar. |
| IN_PROC_BROWSER_TEST_F(BrowserFocusTest, LocationBarLockFocus) { |
| HTTPTestServer* server = StartHTTPServer(); |
| |
| // Open the page that steals focus. |
| GURL url = server->TestServerPageW(kStealFocusPage); |
| ui_test_utils::NavigateToURL(browser(), url); |
| |
| HWND hwnd = reinterpret_cast<HWND>(browser()->window()->GetNativeHandle()); |
| BrowserView* browser_view = BrowserView::GetBrowserViewForHWND(hwnd); |
| views::FocusManager* focus_manager = |
| views::FocusManager::GetFocusManager(hwnd); |
| |
| // Click on the location bar. |
| LocationBarView* location_bar = browser_view->GetLocationBarView(); |
| ui_controls::MoveMouseToCenterAndPress(location_bar, |
| ui_controls::LEFT, |
| ui_controls::DOWN | ui_controls::UP, |
| new MessageLoop::QuitTask()); |
| ui_test_utils::RunMessageLoop(); |
| |
| // Wait for the page to steal focus. |
| ::Sleep(2000); |
| |
| // Make sure the location bar is still focused. |
| EXPECT_EQ(location_bar, focus_manager->GetFocusedView()); |
| } |
| |
| // Focus traversal |
| IN_PROC_BROWSER_TEST_F(BrowserFocusTest, FocusTraversal) { |
| HTTPTestServer* server = StartHTTPServer(); |
| |
| // First we navigate to our test page. |
| GURL url = server->TestServerPageW(kTypicalPage); |
| ui_test_utils::NavigateToURL(browser(), url); |
| |
| HWND hwnd = reinterpret_cast<HWND>(browser()->window()->GetNativeHandle()); |
| BrowserView* browser_view = BrowserView::GetBrowserViewForHWND(hwnd); |
| views::FocusManager* focus_manager = |
| views::FocusManager::GetFocusManager(hwnd); |
| |
| // Click on the location bar. |
| LocationBarView* location_bar = browser_view->GetLocationBarView(); |
| ui_controls::MoveMouseToCenterAndPress(location_bar, |
| ui_controls::LEFT, |
| ui_controls::DOWN | ui_controls::UP, |
| new MessageLoop::QuitTask()); |
| ui_test_utils::RunMessageLoop(); |
| |
| const char* kExpElementIDs[] = { |
| "", // Initially no element in the page should be focused |
| // (the location bar is focused). |
| "textEdit", "searchButton", "luckyButton", "googleLink", "gmailLink", |
| "gmapLink" |
| }; |
| |
| // Test forward focus traversal. |
| for (int i = 0; i < 3; ++i) { |
| // Location bar should be focused. |
| EXPECT_EQ(location_bar, focus_manager->GetFocusedView()); |
| |
| // Now let's press tab to move the focus. |
| for (int j = 0; j < 7; ++j) { |
| // Let's make sure the focus is on the expected element in the page. |
| std::string actual; |
| ASSERT_TRUE(ui_test_utils::ExecuteJavaScriptAndExtractString( |
| browser()->GetSelectedTabContents(), |
| L"", |
| L"window.domAutomationController.send(getFocusedElement());", |
| &actual)); |
| ASSERT_STREQ(kExpElementIDs[j], actual.c_str()); |
| |
| ui_controls::SendKeyPressNotifyWhenDone(L'\t', false, false, false, |
| new MessageLoop::QuitTask()); |
| ui_test_utils::RunMessageLoop(); |
| // Ideally, we wouldn't sleep here and instead would use the event |
| // processed ack notification from the renderer. I am reluctant to create |
| // a new notification/callback for that purpose just for this test. |
| ::Sleep(kActionDelayMs); |
| } |
| |
| // At this point the renderer has sent us a message asking to advance the |
| // focus (as the end of the focus loop was reached in the renderer). |
| // We need to run the message loop to process it. |
| MessageLoop::current()->PostTask(FROM_HERE, new MessageLoop::QuitTask()); |
| ui_test_utils::RunMessageLoop(); |
| } |
| |
| // Now let's try reverse focus traversal. |
| for (int i = 0; i < 3; ++i) { |
| // Location bar should be focused. |
| EXPECT_EQ(location_bar, focus_manager->GetFocusedView()); |
| |
| // Now let's press shift-tab to move the focus in reverse. |
| for (int j = 0; j < 7; ++j) { |
| ui_controls::SendKeyPressNotifyWhenDone(L'\t', false, true, false, |
| new MessageLoop::QuitTask()); |
| ui_test_utils::RunMessageLoop(); |
| ::Sleep(kActionDelayMs); |
| |
| // Let's make sure the focus is on the expected element in the page. |
| std::string actual; |
| ASSERT_TRUE(ui_test_utils::ExecuteJavaScriptAndExtractString( |
| browser()->GetSelectedTabContents(), |
| L"", |
| L"window.domAutomationController.send(getFocusedElement());", |
| &actual)); |
| ASSERT_STREQ(kExpElementIDs[6 - j], actual.c_str()); |
| } |
| |
| // At this point the renderer has sent us a message asking to advance the |
| // focus (as the end of the focus loop was reached in the renderer). |
| // We need to run the message loop to process it. |
| MessageLoop::current()->PostTask(FROM_HERE, new MessageLoop::QuitTask()); |
| ui_test_utils::RunMessageLoop(); |
| } |
| } |
| |
| // Make sure Find box can request focus, even when it is already open. |
| IN_PROC_BROWSER_TEST_F(BrowserFocusTest, FindFocusTest) { |
| HTTPTestServer* server = StartHTTPServer(); |
| |
| // Open some page (any page that doesn't steal focus). |
| GURL url = server->TestServerPageW(kTypicalPage); |
| ui_test_utils::NavigateToURL(browser(), url); |
| |
| HWND hwnd = reinterpret_cast<HWND>(browser()->window()->GetNativeHandle()); |
| BrowserView* browser_view = BrowserView::GetBrowserViewForHWND(hwnd); |
| views::FocusManager* focus_manager = |
| views::FocusManager::GetFocusManager(hwnd); |
| LocationBarView* location_bar = browser_view->GetLocationBarView(); |
| |
| // Press Ctrl+F, which will make the Find box open and request focus. |
| static const int VK_F = 0x46; |
| ui_controls::SendKeyPressNotifyWhenDone(L'F', true, false, false, |
| new MessageLoop::QuitTask()); |
| ui_test_utils::RunMessageLoop(); |
| |
| // Ideally, we wouldn't sleep here and instead would intercept the |
| // RenderViewHostDelegate::HandleKeyboardEvent() callback. To do that, we |
| // could create a RenderViewHostDelegate wrapper and hook-it up by either: |
| // - creating a factory used to create the delegate |
| // - making the test a private and overwriting the delegate member directly. |
| ::Sleep(kActionDelayMs); |
| MessageLoop::current()->PostTask(FROM_HERE, new MessageLoop::QuitTask()); |
| ui_test_utils::RunMessageLoop(); |
| |
| views::View* focused_view = focus_manager->GetFocusedView(); |
| ASSERT_TRUE(focused_view != NULL); |
| EXPECT_EQ(VIEW_ID_FIND_IN_PAGE_TEXT_FIELD, focused_view->GetID()); |
| |
| // Click on the location bar. |
| ui_controls::MoveMouseToCenterAndPress(location_bar, |
| ui_controls::LEFT, |
| ui_controls::DOWN | ui_controls::UP, |
| new MessageLoop::QuitTask()); |
| ui_test_utils::RunMessageLoop(); |
| |
| // Make sure the location bar is focused. |
| EXPECT_EQ(location_bar, focus_manager->GetFocusedView()); |
| |
| // Now press Ctrl+F again and focus should move to the Find box. |
| ui_controls::SendKeyPressNotifyWhenDone(L'F', true, false, false, |
| new MessageLoop::QuitTask()); |
| ui_test_utils::RunMessageLoop(); |
| focused_view = focus_manager->GetFocusedView(); |
| ASSERT_TRUE(focused_view != NULL); |
| EXPECT_EQ(VIEW_ID_FIND_IN_PAGE_TEXT_FIELD, focused_view->GetID()); |
| |
| // Set focus to the page. |
| ui_controls::MoveMouseToCenterAndPress(browser_view->GetContentsView(), |
| ui_controls::LEFT, |
| ui_controls::DOWN | ui_controls::UP, |
| new MessageLoop::QuitTask()); |
| ui_test_utils::RunMessageLoop(); |
| EXPECT_EQ(browser_view->GetContentsView(), focus_manager->GetFocusedView()); |
| |
| // Now press Ctrl+F again and focus should move to the Find box. |
| ui_controls::SendKeyPressNotifyWhenDone(VK_F, true, false, false, |
| new MessageLoop::QuitTask()); |
| ui_test_utils::RunMessageLoop(); |
| |
| // See remark above on why we wait. |
| ::Sleep(kActionDelayMs); |
| MessageLoop::current()->PostTask(FROM_HERE, new MessageLoop::QuitTask()); |
| ui_test_utils::RunMessageLoop(); |
| |
| focused_view = focus_manager->GetFocusedView(); |
| ASSERT_TRUE(focused_view != NULL); |
| EXPECT_EQ(VIEW_ID_FIND_IN_PAGE_TEXT_FIELD, focused_view->GetID()); |
| } |
| |
| // Makes sure the focus is in the right location when opening the different |
| // types of tabs. |
| IN_PROC_BROWSER_TEST_F(BrowserFocusTest, TabInitialFocus) { |
| HWND hwnd = reinterpret_cast<HWND>(browser()->window()->GetNativeHandle()); |
| BrowserView* browser_view = BrowserView::GetBrowserViewForHWND(hwnd); |
| ASSERT_TRUE(browser_view); |
| views::FocusManager* focus_manager = |
| views::FocusManager::GetFocusManager(hwnd); |
| ASSERT_TRUE(focus_manager); |
| |
| // Open the history tab, focus should be on the tab contents. |
| browser()->ShowHistoryTab(); |
| EXPECT_EQ(browser_view->GetContentsView(), focus_manager->GetFocusedView()); |
| |
| // Open the new tab, focus should be on the location bar. |
| browser()->NewTab(); |
| EXPECT_EQ(browser_view->GetLocationBarView(), |
| focus_manager->GetFocusedView()); |
| |
| // Open the download tab, focus should be on the tab contents. |
| browser()->ShowDownloadsTab(); |
| EXPECT_EQ(browser_view->GetContentsView(), focus_manager->GetFocusedView()); |
| } |