| // Copyright 2018 The Chromium Authors |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #include "content/browser/keyboard_lock_browsertest.h" |
| |
| #include <string> |
| |
| #include "base/metrics/histogram_base.h" |
| #include "base/test/metrics/histogram_tester.h" |
| #include "base/test/scoped_feature_list.h" |
| #include "build/build_config.h" |
| #include "content/browser/keyboard_lock/keyboard_lock_metrics.h" |
| #include "content/browser/renderer_host/render_widget_host_impl.h" |
| #include "content/browser/web_contents/web_contents_impl.h" |
| #include "content/public/common/content_features.h" |
| #include "content/public/test/browser_test.h" |
| #include "content/public/test/browser_test_utils.h" |
| #include "content/public/test/content_browser_test.h" |
| #include "content/public/test/content_browser_test_utils.h" |
| #include "content/public/test/content_mock_cert_verifier.h" |
| #include "content/public/test/test_utils.h" |
| #include "content/shell/browser/shell.h" |
| #include "content/test/content_browser_test_utils_internal.h" |
| #include "net/dns/mock_host_resolver.h" |
| #include "net/test/embedded_test_server/embedded_test_server.h" |
| #include "third_party/blink/public/mojom/frame/fullscreen.mojom.h" |
| #include "ui/events/keycodes/dom/dom_code.h" |
| #include "ui/events/keycodes/dom/keycode_converter.h" |
| #include "ui/events/keycodes/keyboard_code_conversion.h" |
| #include "ui/events/keycodes/keyboard_codes.h" |
| #include "ui/gfx/native_widget_types.h" |
| |
| #ifdef USE_AURA |
| #include "content/browser/renderer_host/render_widget_host_view_aura.h" |
| #include "content/browser/web_contents/web_contents_view_aura.h" |
| #endif // USE_AURA |
| |
| namespace content { |
| |
| namespace { |
| |
| constexpr char kFullscreenFramePath[] = "/fullscreen_frame.html"; |
| |
| constexpr char kHelloFramePath[] = "/hello.html"; |
| |
| constexpr char kInputFieldFramePath[] = "/page_with_input_field.html"; |
| |
| // Set up a DOM structure which contains three inner iframes for testing: |
| // - Same domain iframe w/ fullscreen attribute. |
| // - Cross domain iframe. |
| // - Cross domain iframe w/ fullscreen attribute. |
| constexpr char kCrossSiteFramePath[] = |
| "/cross_site_iframe_factory.html" |
| "?a(a{allowfullscreen}(),b(),c{allowfullscreen}())"; |
| |
| constexpr char kCrossSiteTopLevelDomain[] = "a.com"; |
| |
| constexpr char kChildIframeName_0[] = "child-0"; |
| |
| constexpr char kChildIframeName_1[] = "child-1"; |
| |
| constexpr char kChildIframeName_2[] = "child-2"; |
| |
| constexpr char kCrossSiteChildDomain1[] = "b.com"; |
| |
| constexpr char kCrossSiteChildDomain2[] = "c.com"; |
| |
| constexpr char kKeyboardLockMethodExistanceCheck[] = |
| "(navigator.keyboard != undefined) &&" |
| "(navigator.keyboard.lock != undefined);"; |
| |
| constexpr char kKeyboardLockMethodCallWithAllKeys[] = |
| "navigator.keyboard.lock().then(" |
| " () => true," |
| " () => false," |
| ");"; |
| |
| constexpr char kKeyboardLockMethodCallWithSomeKeys[] = |
| "navigator.keyboard.lock(['MetaLeft', 'Tab', 'AltLeft']).then(" |
| " () => true," |
| " () => false," |
| ");"; |
| |
| // Calling lock() with no valid key codes will cause the promise to be rejected. |
| constexpr char kKeyboardLockMethodCallWithAllInvalidKeys[] = |
| "navigator.keyboard.lock(['BlerghLeft', 'BlarghRight']).then(" |
| " () => false," |
| " () => true," |
| ");"; |
| |
| // Calling lock() with some invalid key codes will reject the promise. |
| constexpr char kKeyboardLockMethodCallWithSomeInvalidKeys[] = |
| "navigator.keyboard.lock(['Tab', 'BlarghTab', 'Space', 'BlerghLeft']).then(" |
| " () => false," |
| " () => true," |
| ");"; |
| |
| constexpr char kKeyboardUnlockMethodCall[] = "navigator.keyboard.unlock()"; |
| |
| constexpr char kFocusInputFieldScript[] = |
| "function onInput(e) {" |
| " resultQueue.push(getInputFieldText());" |
| "}" |
| "inputField = document.getElementById('text-field');" |
| "inputField.addEventListener('input', onInput, false);"; |
| |
| void SimulateKeyPress(WebContents* web_contents, |
| RenderFrameHost* event_recipient, |
| const std::string& code_string, |
| const std::string& expected_result) { |
| ui::DomKey dom_key = ui::KeycodeConverter::KeyStringToDomKey(code_string); |
| ui::DomCode dom_code = ui::KeycodeConverter::CodeStringToDomCode(code_string); |
| SimulateKeyPress(web_contents, dom_key, dom_code, |
| ui::DomCodeToUsLayoutKeyboardCode(dom_code), false, false, |
| false, false); |
| ASSERT_EQ(expected_result, EvalJs(event_recipient, "waitForInput()")); |
| } |
| |
| #if defined(USE_AURA) |
| |
| bool g_window_has_focus = false; |
| |
| class TestRenderWidgetHostView : public RenderWidgetHostViewAura { |
| public: |
| explicit TestRenderWidgetHostView(RenderWidgetHost* host) |
| : RenderWidgetHostViewAura(host) {} |
| ~TestRenderWidgetHostView() override {} |
| |
| bool HasFocus() override { return g_window_has_focus; } |
| |
| void OnWindowFocused(aura::Window* gained_focus, |
| aura::Window* lost_focus) override { |
| // Ignore all focus events. |
| } |
| }; |
| |
| #endif // USE_AURA |
| |
| class FakeKeyboardLockWebContentsDelegate : public WebContentsDelegate { |
| public: |
| FakeKeyboardLockWebContentsDelegate() {} |
| |
| FakeKeyboardLockWebContentsDelegate( |
| const FakeKeyboardLockWebContentsDelegate&) = delete; |
| FakeKeyboardLockWebContentsDelegate& operator=( |
| const FakeKeyboardLockWebContentsDelegate&) = delete; |
| |
| ~FakeKeyboardLockWebContentsDelegate() override {} |
| |
| // WebContentsDelegate overrides. |
| void EnterFullscreenModeForTab( |
| RenderFrameHost* requesting_frame, |
| const blink::mojom::FullscreenOptions& options) override; |
| void ExitFullscreenModeForTab(WebContents* web_contents) override; |
| bool IsFullscreenForTabOrPending(const WebContents* web_contents) override; |
| void RequestKeyboardLock(WebContents* web_contents, |
| bool esc_key_locked) override; |
| void CancelKeyboardLockRequest(WebContents* web_contents) override; |
| |
| private: |
| bool is_fullscreen_ = false; |
| bool keyboard_lock_requested_ = false; |
| }; |
| |
| void FakeKeyboardLockWebContentsDelegate::EnterFullscreenModeForTab( |
| RenderFrameHost* requesting_frame, |
| const blink::mojom::FullscreenOptions& options) { |
| is_fullscreen_ = true; |
| auto* web_contents = WebContents::FromRenderFrameHost(requesting_frame); |
| if (keyboard_lock_requested_) |
| web_contents->GotResponseToKeyboardLockRequest(/*allowed=*/true); |
| } |
| |
| void FakeKeyboardLockWebContentsDelegate::ExitFullscreenModeForTab( |
| WebContents* web_contents) { |
| is_fullscreen_ = false; |
| if (keyboard_lock_requested_) |
| web_contents->GotResponseToKeyboardLockRequest(/*allowed=*/false); |
| } |
| |
| bool FakeKeyboardLockWebContentsDelegate::IsFullscreenForTabOrPending( |
| const WebContents* web_contents) { |
| return is_fullscreen_; |
| } |
| |
| void FakeKeyboardLockWebContentsDelegate::RequestKeyboardLock( |
| WebContents* web_contents, |
| bool esc_key_locked) { |
| keyboard_lock_requested_ = true; |
| web_contents->GotResponseToKeyboardLockRequest(/*allowed=*/true); |
| } |
| |
| void FakeKeyboardLockWebContentsDelegate::CancelKeyboardLockRequest( |
| WebContents* web_contents) { |
| keyboard_lock_requested_ = false; |
| } |
| |
| } // namespace |
| |
| #if defined(USE_AURA) |
| |
| void SetWindowFocusForKeyboardLockBrowserTests(bool is_focused) { |
| g_window_has_focus = is_focused; |
| } |
| |
| void InstallCreateHooksForKeyboardLockBrowserTests() { |
| WebContentsViewAura::InstallCreateHookForTests( |
| [](RenderWidgetHost* host) -> RenderWidgetHostViewAura* { |
| return new TestRenderWidgetHostView(host); |
| }); |
| } |
| |
| #endif // USE_AURA |
| |
| class KeyboardLockBrowserTest : public ContentBrowserTest { |
| public: |
| KeyboardLockBrowserTest(); |
| ~KeyboardLockBrowserTest() override; |
| |
| protected: |
| // ContentBrowserTest overrides. |
| void SetUp() override; |
| void SetUpCommandLine(base::CommandLine* command_line) override; |
| void SetUpOnMainThread() override; |
| void SetUpInProcessBrowserTestFixture() override; |
| void TearDownInProcessBrowserTestFixture() override; |
| |
| // Helper methods for common tasks. |
| bool KeyboardLockApiExists(); |
| void NavigateToTestURL(const GURL& gurl); |
| void RequestKeyboardLock(const base::Location& from_here, |
| bool lock_all_keys = true); |
| void CancelKeyboardLock(const base::Location& from_here); |
| void EnterFullscreen(const base::Location& from_here); |
| void ExitFullscreen(const base::Location& from_here); |
| void FocusContent(const base::Location& from_here); |
| void BlurContent(const base::Location& from_here); |
| void VerifyKeyboardLockState(const base::Location& from_here); |
| |
| WebContentsImpl* web_contents() const { |
| return static_cast<WebContentsImpl*>(shell()->web_contents()); |
| } |
| |
| net::EmbeddedTestServer* https_test_server() { return &https_test_server_; } |
| |
| GURL https_fullscreen_frame() { |
| return https_test_server()->GetURL(kFullscreenFramePath); |
| } |
| |
| GURL https_cross_site_frame() { |
| return https_test_server()->GetURL(kCrossSiteTopLevelDomain, |
| kCrossSiteFramePath); |
| } |
| |
| base::test::ScopedFeatureList* feature_list() { |
| return &scoped_feature_list_; |
| } |
| |
| WebContentsDelegate* web_contents_delegate() { |
| return &web_contents_delegate_; |
| } |
| |
| private: |
| content::ContentMockCertVerifier mock_cert_verifier_; |
| base::test::ScopedFeatureList scoped_feature_list_; |
| net::EmbeddedTestServer https_test_server_; |
| FakeKeyboardLockWebContentsDelegate web_contents_delegate_; |
| }; |
| |
| KeyboardLockBrowserTest::KeyboardLockBrowserTest() |
| : https_test_server_(net::EmbeddedTestServer::TYPE_HTTPS) {} |
| |
| KeyboardLockBrowserTest::~KeyboardLockBrowserTest() = default; |
| |
| void KeyboardLockBrowserTest::SetUp() { |
| // Assume we have focus to start with. |
| SetWindowFocusForKeyboardLockBrowserTests(true); |
| InstallCreateHooksForKeyboardLockBrowserTests(); |
| ContentBrowserTest::SetUp(); |
| } |
| |
| void KeyboardLockBrowserTest::SetUpCommandLine( |
| base::CommandLine* command_line) { |
| mock_cert_verifier_.SetUpCommandLine(command_line); |
| } |
| |
| void KeyboardLockBrowserTest::SetUpOnMainThread() { |
| ContentBrowserTest::SetUpOnMainThread(); |
| mock_cert_verifier_.mock_cert_verifier()->set_default_result(net::OK); |
| |
| web_contents()->SetDelegate(&web_contents_delegate_); |
| |
| // KeyboardLock requires a secure context (HTTPS). |
| https_test_server()->AddDefaultHandlers(GetTestDataFilePath()); |
| host_resolver()->AddRule("*", "127.0.0.1"); |
| SetupCrossSiteRedirector(https_test_server()); |
| ASSERT_TRUE(https_test_server()->Start()); |
| } |
| |
| void KeyboardLockBrowserTest::SetUpInProcessBrowserTestFixture() { |
| ContentBrowserTest::SetUpInProcessBrowserTestFixture(); |
| mock_cert_verifier_.SetUpInProcessBrowserTestFixture(); |
| } |
| |
| void KeyboardLockBrowserTest::TearDownInProcessBrowserTestFixture() { |
| ContentBrowserTest::TearDownInProcessBrowserTestFixture(); |
| mock_cert_verifier_.TearDownInProcessBrowserTestFixture(); |
| } |
| |
| bool KeyboardLockBrowserTest::KeyboardLockApiExists() { |
| return EvalJs(web_contents(), kKeyboardLockMethodExistanceCheck) |
| .ExtractBool(); |
| } |
| |
| void KeyboardLockBrowserTest::NavigateToTestURL(const GURL& gurl) { |
| ASSERT_TRUE(NavigateToURL(shell(), gurl)); |
| |
| ASSERT_TRUE(KeyboardLockApiExists()); |
| |
| // Ensure the window has focus and is in windowed mode after the navigation. |
| FocusContent(FROM_HERE); |
| ExitFullscreen(FROM_HERE); |
| } |
| |
| void KeyboardLockBrowserTest::RequestKeyboardLock( |
| const base::Location& from_here, |
| bool lock_all_keys /*=true*/) { |
| // keyboard.lock() is an async call which requires a promise handling dance. |
| bool result = EvalJs(web_contents()->GetPrimaryMainFrame(), |
| lock_all_keys ? kKeyboardLockMethodCallWithAllKeys |
| : kKeyboardLockMethodCallWithSomeKeys) |
| .ExtractBool(); |
| |
| ASSERT_TRUE(result) << "Location: " << from_here.ToString(); |
| |
| ASSERT_EQ(result, web_contents()->GetKeyboardLockWidget() != nullptr) |
| << "Location: " << from_here.ToString(); |
| |
| VerifyKeyboardLockState(from_here); |
| } |
| |
| void KeyboardLockBrowserTest::CancelKeyboardLock( |
| const base::Location& from_here) { |
| // keyboard.unlock() is a synchronous call. |
| ASSERT_TRUE( |
| ExecJs(web_contents()->GetPrimaryMainFrame(), kKeyboardUnlockMethodCall)); |
| |
| ASSERT_EQ(nullptr, web_contents()->GetKeyboardLockWidget()) |
| << "Location: " << from_here.ToString(); |
| |
| VerifyKeyboardLockState(from_here); |
| } |
| |
| void KeyboardLockBrowserTest::EnterFullscreen(const base::Location& from_here) { |
| web_contents()->EnterFullscreenMode(web_contents()->GetPrimaryMainFrame(), |
| {}); |
| |
| ASSERT_TRUE(web_contents()->IsFullscreen()) |
| << "Location: " << from_here.ToString(); |
| |
| VerifyKeyboardLockState(from_here); |
| } |
| |
| void KeyboardLockBrowserTest::ExitFullscreen(const base::Location& from_here) { |
| web_contents()->ExitFullscreenMode(/*should_resize=*/true); |
| |
| ASSERT_FALSE(web_contents()->IsFullscreen()) |
| << "Location: " << from_here.ToString(); |
| |
| VerifyKeyboardLockState(from_here); |
| } |
| |
| void KeyboardLockBrowserTest::FocusContent(const base::Location& from_here) { |
| SetWindowFocusForKeyboardLockBrowserTests(true); |
| RenderWidgetHostImpl* host = RenderWidgetHostImpl::From( |
| web_contents()->GetRenderWidgetHostView()->GetRenderWidgetHost()); |
| host->GotFocus(); |
| host->SetActive(true); |
| |
| ASSERT_TRUE(web_contents()->GetRenderWidgetHostView()->HasFocus()) |
| << "Location: " << from_here.ToString(); |
| |
| VerifyKeyboardLockState(from_here); |
| } |
| |
| void KeyboardLockBrowserTest::BlurContent(const base::Location& from_here) { |
| SetWindowFocusForKeyboardLockBrowserTests(false); |
| RenderWidgetHostImpl* host = RenderWidgetHostImpl::From( |
| web_contents()->GetRenderWidgetHostView()->GetRenderWidgetHost()); |
| host->SetActive(false); |
| host->LostFocus(); |
| |
| ASSERT_FALSE(web_contents()->GetRenderWidgetHostView()->HasFocus()) |
| << "Location: " << from_here.ToString(); |
| |
| VerifyKeyboardLockState(from_here); |
| } |
| |
| void KeyboardLockBrowserTest::VerifyKeyboardLockState( |
| const base::Location& from_here) { |
| bool keyboard_lock_requested = !!web_contents()->GetKeyboardLockWidget(); |
| |
| bool ux_conditions_satisfied = |
| web_contents()->GetRenderWidgetHostView()->HasFocus() && |
| web_contents()->IsFullscreen(); |
| |
| bool keyboard_lock_active = |
| web_contents()->GetRenderWidgetHostView()->IsKeyboardLocked(); |
| |
| // Keyboard lock only active when requested and the UX is in the right state. |
| ASSERT_EQ(keyboard_lock_active, |
| ux_conditions_satisfied && keyboard_lock_requested) |
| << "Location: " << from_here.ToString(); |
| } |
| |
| IN_PROC_BROWSER_TEST_F(KeyboardLockBrowserTest, SingleLockCall) { |
| NavigateToTestURL(https_fullscreen_frame()); |
| base::HistogramTester uma; |
| RequestKeyboardLock(FROM_HERE); |
| // Don't explicitly call CancelKeyboardLock(). |
| |
| uma.ExpectTotalCount(kKeyboardLockMethodCalledHistogramName, 1); |
| uma.ExpectBucketCount(kKeyboardLockMethodCalledHistogramName, |
| static_cast<int>(KeyboardLockMethods::kRequestAllKeys), |
| 1); |
| } |
| |
| IN_PROC_BROWSER_TEST_F(KeyboardLockBrowserTest, SingleLockCallForSomeKeys) { |
| NavigateToTestURL(https_fullscreen_frame()); |
| base::HistogramTester uma; |
| RequestKeyboardLock(FROM_HERE, /*lock_all_keys=*/false); |
| // Don't explicitly call CancelKeyboardLock(). |
| |
| uma.ExpectTotalCount(kKeyboardLockMethodCalledHistogramName, 1); |
| uma.ExpectBucketCount(kKeyboardLockMethodCalledHistogramName, |
| static_cast<int>(KeyboardLockMethods::kRequestSomeKeys), |
| 1); |
| } |
| |
| IN_PROC_BROWSER_TEST_F(KeyboardLockBrowserTest, SingleLockWithCancelCall) { |
| NavigateToTestURL(https_fullscreen_frame()); |
| base::HistogramTester uma; |
| RequestKeyboardLock(FROM_HERE); |
| CancelKeyboardLock(FROM_HERE); |
| |
| uma.ExpectTotalCount(kKeyboardLockMethodCalledHistogramName, 2); |
| uma.ExpectBucketCount(kKeyboardLockMethodCalledHistogramName, |
| static_cast<int>(KeyboardLockMethods::kRequestAllKeys), |
| 1); |
| uma.ExpectBucketCount(kKeyboardLockMethodCalledHistogramName, |
| static_cast<int>(KeyboardLockMethods::kCancelLock), 1); |
| } |
| |
| IN_PROC_BROWSER_TEST_F(KeyboardLockBrowserTest, LockCalledBeforeFullscreen) { |
| GURL url_for_test = https_fullscreen_frame(); |
| NavigateToTestURL(url_for_test); |
| RequestKeyboardLock(FROM_HERE); |
| EnterFullscreen(FROM_HERE); |
| } |
| |
| IN_PROC_BROWSER_TEST_F(KeyboardLockBrowserTest, LockCalledAfterFullscreen) { |
| GURL url_for_test = https_fullscreen_frame(); |
| NavigateToTestURL(url_for_test); |
| EnterFullscreen(FROM_HERE); |
| RequestKeyboardLock(FROM_HERE); |
| } |
| |
| IN_PROC_BROWSER_TEST_F(KeyboardLockBrowserTest, |
| LockAndCancelCyclingNoActivation) { |
| NavigateToTestURL(https_fullscreen_frame()); |
| |
| base::HistogramTester uma; |
| RequestKeyboardLock(FROM_HERE); |
| CancelKeyboardLock(FROM_HERE); |
| RequestKeyboardLock(FROM_HERE, /*lock_all_keys=*/false); |
| CancelKeyboardLock(FROM_HERE); |
| RequestKeyboardLock(FROM_HERE); |
| CancelKeyboardLock(FROM_HERE); |
| RequestKeyboardLock(FROM_HERE); |
| CancelKeyboardLock(FROM_HERE); |
| |
| uma.ExpectTotalCount(kKeyboardLockMethodCalledHistogramName, 8); |
| uma.ExpectBucketCount(kKeyboardLockMethodCalledHistogramName, |
| static_cast<int>(KeyboardLockMethods::kRequestAllKeys), |
| 3); |
| uma.ExpectBucketCount(kKeyboardLockMethodCalledHistogramName, |
| static_cast<int>(KeyboardLockMethods::kRequestSomeKeys), |
| 1); |
| uma.ExpectBucketCount(kKeyboardLockMethodCalledHistogramName, |
| static_cast<int>(KeyboardLockMethods::kCancelLock), 4); |
| } |
| |
| IN_PROC_BROWSER_TEST_F(KeyboardLockBrowserTest, |
| LockAndCancelCyclingInFullscreen) { |
| GURL url_for_test = https_fullscreen_frame(); |
| NavigateToTestURL(url_for_test); |
| |
| EnterFullscreen(FROM_HERE); |
| |
| RequestKeyboardLock(FROM_HERE); |
| CancelKeyboardLock(FROM_HERE); |
| RequestKeyboardLock(FROM_HERE, /*lock_all_keys=*/false); |
| CancelKeyboardLock(FROM_HERE); |
| RequestKeyboardLock(FROM_HERE, /*lock_all_keys=*/false); |
| CancelKeyboardLock(FROM_HERE); |
| RequestKeyboardLock(FROM_HERE); |
| CancelKeyboardLock(FROM_HERE); |
| RequestKeyboardLock(FROM_HERE); |
| CancelKeyboardLock(FROM_HERE); |
| } |
| |
| IN_PROC_BROWSER_TEST_F(KeyboardLockBrowserTest, CancelInFullscreen) { |
| GURL url_for_test = https_fullscreen_frame(); |
| NavigateToTestURL(url_for_test); |
| |
| RequestKeyboardLock(FROM_HERE); |
| EnterFullscreen(FROM_HERE); |
| CancelKeyboardLock(FROM_HERE); |
| ExitFullscreen(FROM_HERE); |
| } |
| |
| IN_PROC_BROWSER_TEST_F(KeyboardLockBrowserTest, EnterAndExitFullscreenCycling) { |
| GURL url_for_test = https_fullscreen_frame(); |
| NavigateToTestURL(url_for_test); |
| |
| RequestKeyboardLock(FROM_HERE); |
| |
| EnterFullscreen(FROM_HERE); |
| ExitFullscreen(FROM_HERE); |
| EnterFullscreen(FROM_HERE); |
| ExitFullscreen(FROM_HERE); |
| EnterFullscreen(FROM_HERE); |
| ExitFullscreen(FROM_HERE); |
| EnterFullscreen(FROM_HERE); |
| ExitFullscreen(FROM_HERE); |
| } |
| |
| IN_PROC_BROWSER_TEST_F(KeyboardLockBrowserTest, GainAndLoseFocusInWindowMode) { |
| NavigateToTestURL(https_fullscreen_frame()); |
| |
| RequestKeyboardLock(FROM_HERE); |
| |
| FocusContent(FROM_HERE); |
| BlurContent(FROM_HERE); |
| FocusContent(FROM_HERE); |
| BlurContent(FROM_HERE); |
| } |
| |
| IN_PROC_BROWSER_TEST_F(KeyboardLockBrowserTest, EnterFullscreenWithoutFocus) { |
| GURL url_for_test = https_fullscreen_frame(); |
| NavigateToTestURL(url_for_test); |
| |
| RequestKeyboardLock(FROM_HERE); |
| |
| BlurContent(FROM_HERE); |
| EnterFullscreen(FROM_HERE); |
| ExitFullscreen(FROM_HERE); |
| |
| EnterFullscreen(FROM_HERE); |
| FocusContent(FROM_HERE); |
| } |
| |
| IN_PROC_BROWSER_TEST_F(KeyboardLockBrowserTest, |
| GainAndLoseFocusCyclingInFullscreen) { |
| GURL url_for_test = https_fullscreen_frame(); |
| NavigateToTestURL(url_for_test); |
| |
| RequestKeyboardLock(FROM_HERE); |
| |
| BlurContent(FROM_HERE); |
| EnterFullscreen(FROM_HERE); |
| |
| FocusContent(FROM_HERE); |
| BlurContent(FROM_HERE); |
| FocusContent(FROM_HERE); |
| BlurContent(FROM_HERE); |
| FocusContent(FROM_HERE); |
| BlurContent(FROM_HERE); |
| FocusContent(FROM_HERE); |
| BlurContent(FROM_HERE); |
| |
| ExitFullscreen(FROM_HERE); |
| } |
| |
| IN_PROC_BROWSER_TEST_F(KeyboardLockBrowserTest, CancelWithoutLock) { |
| NavigateToTestURL(https_fullscreen_frame()); |
| CancelKeyboardLock(FROM_HERE); |
| CancelKeyboardLock(FROM_HERE); |
| } |
| |
| IN_PROC_BROWSER_TEST_F(KeyboardLockBrowserTest, MultipleLockCalls) { |
| NavigateToTestURL(https_fullscreen_frame()); |
| |
| RequestKeyboardLock(FROM_HERE); |
| RequestKeyboardLock(FROM_HERE); |
| RequestKeyboardLock(FROM_HERE); |
| } |
| |
| IN_PROC_BROWSER_TEST_F(KeyboardLockBrowserTest, MultipleCancelCalls) { |
| NavigateToTestURL(https_fullscreen_frame()); |
| |
| RequestKeyboardLock(FROM_HERE); |
| |
| CancelKeyboardLock(FROM_HERE); |
| CancelKeyboardLock(FROM_HERE); |
| CancelKeyboardLock(FROM_HERE); |
| } |
| |
| IN_PROC_BROWSER_TEST_F(KeyboardLockBrowserTest, LockCallWithAllInvalidKeys) { |
| GURL url_for_test = https_fullscreen_frame(); |
| NavigateToTestURL(url_for_test); |
| |
| ASSERT_EQ(true, |
| EvalJs(web_contents(), kKeyboardLockMethodCallWithAllInvalidKeys)); |
| |
| // If no valid Keys are passed in, then keyboard lock will not be requested. |
| ASSERT_FALSE(web_contents()->GetKeyboardLockWidget()); |
| |
| EnterFullscreen(FROM_HERE); |
| } |
| |
| IN_PROC_BROWSER_TEST_F(KeyboardLockBrowserTest, LockCallWithSomeInvalidKeys) { |
| GURL url_for_test = https_fullscreen_frame(); |
| NavigateToTestURL(url_for_test); |
| |
| ASSERT_EQ(true, |
| EvalJs(web_contents(), kKeyboardLockMethodCallWithSomeInvalidKeys)); |
| |
| // If some valid Keys are passed in, then keyboard lock will not be requested. |
| ASSERT_FALSE(web_contents()->GetKeyboardLockWidget()); |
| } |
| |
| IN_PROC_BROWSER_TEST_F(KeyboardLockBrowserTest, |
| ValidLockCallFollowedByInvalidLockCall) { |
| NavigateToTestURL(https_fullscreen_frame()); |
| |
| RequestKeyboardLock(FROM_HERE); |
| ASSERT_TRUE(web_contents()->GetKeyboardLockWidget()); |
| |
| ASSERT_EQ(true, |
| EvalJs(web_contents(), kKeyboardLockMethodCallWithSomeInvalidKeys)); |
| |
| // An invalid call will cancel any previous lock request. |
| ASSERT_FALSE(web_contents()->GetKeyboardLockWidget()); |
| } |
| |
| IN_PROC_BROWSER_TEST_F(KeyboardLockBrowserTest, |
| KeyboardLockNotAllowedForSameOriginIFrame) { |
| NavigateToTestURL(https_cross_site_frame()); |
| |
| // The first child has the same origin as the top-level domain. |
| RenderFrameHost* child_frame = |
| ChildFrameAt(web_contents()->GetPrimaryMainFrame(), |
| /*index=*/0); |
| ASSERT_TRUE(child_frame); |
| |
| ASSERT_EQ(true, EvalJs(child_frame, kKeyboardLockMethodExistanceCheck)); |
| |
| ASSERT_EQ(false, EvalJs(child_frame, kKeyboardLockMethodCallWithAllKeys)); |
| |
| ASSERT_FALSE(web_contents()->GetKeyboardLockWidget()); |
| } |
| |
| IN_PROC_BROWSER_TEST_F(KeyboardLockBrowserTest, |
| KeyboardLockNotAllowedForCrossOriginIFrame) { |
| NavigateToTestURL(https_cross_site_frame()); |
| |
| // The second child has a different origin as the top-level domain. |
| RenderFrameHost* child_frame = |
| ChildFrameAt(web_contents()->GetPrimaryMainFrame(), |
| /*index=*/1); |
| ASSERT_TRUE(child_frame); |
| |
| ASSERT_EQ(true, EvalJs(child_frame, kKeyboardLockMethodExistanceCheck)); |
| |
| ASSERT_EQ(false, EvalJs(child_frame, kKeyboardLockMethodCallWithAllKeys)); |
| |
| ASSERT_FALSE(web_contents()->GetKeyboardLockWidget()); |
| } |
| |
| IN_PROC_BROWSER_TEST_F(KeyboardLockBrowserTest, |
| KeyboardUnlockedWhenNavigatingToSameUrl) { |
| GURL url_for_test = https_fullscreen_frame(); |
| NavigateToTestURL(url_for_test); |
| EnterFullscreen(FROM_HERE); |
| RequestKeyboardLock(FROM_HERE); |
| |
| // Navigate to the same URL which will reset the keyboard lock state. |
| NavigateToTestURL(url_for_test); |
| ASSERT_FALSE(web_contents()->GetKeyboardLockWidget()); |
| |
| // Entering fullscreen on the new page should not engage keyboard lock. |
| EnterFullscreen(FROM_HERE); |
| ASSERT_FALSE(web_contents()->GetRenderWidgetHostView()->IsKeyboardLocked()); |
| } |
| |
| IN_PROC_BROWSER_TEST_F(KeyboardLockBrowserTest, |
| KeyboardUnlockedWhenNavigatingAway) { |
| GURL first_url_for_test = https_fullscreen_frame(); |
| NavigateToTestURL(first_url_for_test); |
| EnterFullscreen(FROM_HERE); |
| RequestKeyboardLock(FROM_HERE); |
| |
| // Navigate to a new URL which will reset the keyboard lock state. |
| GURL second_url_for_test = https_cross_site_frame(); |
| NavigateToTestURL(second_url_for_test); |
| ASSERT_FALSE(web_contents()->GetKeyboardLockWidget()); |
| |
| // Entering fullscreen on the new page should not engage keyboard lock. |
| EnterFullscreen(FROM_HERE); |
| ASSERT_FALSE(web_contents()->GetRenderWidgetHostView()->IsKeyboardLocked()); |
| } |
| |
| IN_PROC_BROWSER_TEST_F(KeyboardLockBrowserTest, |
| KeyboardRemainsLockedWhenIframeNavigates) { |
| NavigateToTestURL(https_cross_site_frame()); |
| EnterFullscreen(FROM_HERE); |
| RequestKeyboardLock(FROM_HERE); |
| |
| ASSERT_TRUE(NavigateIframeToURL( |
| web_contents(), kChildIframeName_0, |
| https_test_server()->GetURL(kCrossSiteTopLevelDomain, kHelloFramePath))); |
| ASSERT_TRUE(web_contents()->GetKeyboardLockWidget()); |
| ASSERT_TRUE(web_contents()->GetRenderWidgetHostView()->IsKeyboardLocked()); |
| |
| ASSERT_TRUE(NavigateIframeToURL( |
| web_contents(), kChildIframeName_1, |
| https_test_server()->GetURL(kCrossSiteChildDomain1, kHelloFramePath))); |
| ASSERT_TRUE(web_contents()->GetKeyboardLockWidget()); |
| ASSERT_TRUE(web_contents()->GetRenderWidgetHostView()->IsKeyboardLocked()); |
| |
| ASSERT_TRUE(NavigateIframeToURL( |
| web_contents(), kChildIframeName_2, |
| https_test_server()->GetURL(kCrossSiteChildDomain2, kHelloFramePath))); |
| ASSERT_TRUE(web_contents()->GetKeyboardLockWidget()); |
| ASSERT_TRUE(web_contents()->GetRenderWidgetHostView()->IsKeyboardLocked()); |
| |
| ASSERT_TRUE( |
| NavigateIframeToURL(web_contents(), kChildIframeName_0, |
| https_test_server()->GetURL(kCrossSiteChildDomain2, |
| kInputFieldFramePath))); |
| ASSERT_TRUE(web_contents()->GetKeyboardLockWidget()); |
| ASSERT_TRUE(web_contents()->GetRenderWidgetHostView()->IsKeyboardLocked()); |
| |
| ASSERT_TRUE( |
| NavigateIframeToURL(web_contents(), kChildIframeName_1, |
| https_test_server()->GetURL(kCrossSiteTopLevelDomain, |
| kInputFieldFramePath))); |
| ASSERT_TRUE(web_contents()->GetKeyboardLockWidget()); |
| ASSERT_TRUE(web_contents()->GetRenderWidgetHostView()->IsKeyboardLocked()); |
| |
| ASSERT_TRUE( |
| NavigateIframeToURL(web_contents(), kChildIframeName_2, |
| https_test_server()->GetURL(kCrossSiteChildDomain1, |
| kInputFieldFramePath))); |
| ASSERT_TRUE(web_contents()->GetKeyboardLockWidget()); |
| ASSERT_TRUE(web_contents()->GetRenderWidgetHostView()->IsKeyboardLocked()); |
| } |
| |
| IN_PROC_BROWSER_TEST_F(KeyboardLockBrowserTest, |
| CrossOriginIFrameReceivesInputWhenFocused) { |
| NavigateToTestURL(https_cross_site_frame()); |
| EnterFullscreen(FROM_HERE); |
| RequestKeyboardLock(FROM_HERE); |
| |
| GURL iframe_url = |
| https_test_server()->GetURL(kCrossSiteChildDomain1, kInputFieldFramePath); |
| ASSERT_TRUE( |
| NavigateIframeToURL(web_contents(), kChildIframeName_1, iframe_url)); |
| ASSERT_TRUE(web_contents()->GetRenderWidgetHostView()->IsKeyboardLocked()); |
| |
| RenderFrameHost* main_frame = web_contents()->GetPrimaryMainFrame(); |
| RenderFrameHost* child = ChildFrameAt(main_frame, 1); |
| ASSERT_TRUE(child); |
| |
| ASSERT_EQ(main_frame, web_contents()->GetFocusedFrame()); |
| |
| ASSERT_TRUE(ExecJs(child, kFocusInputFieldScript)); |
| ASSERT_EQ("input-focus", EvalJs(child, "window.focus(); focusInputField();")); |
| ASSERT_EQ(child, web_contents()->GetFocusedFrame()); |
| ASSERT_TRUE(web_contents()->GetRenderWidgetHostView()->IsKeyboardLocked()); |
| |
| SimulateKeyPress(web_contents(), child, "KeyB", "B"); |
| SimulateKeyPress(web_contents(), child, "KeyL", "BL"); |
| SimulateKeyPress(web_contents(), child, "KeyA", "BLA"); |
| SimulateKeyPress(web_contents(), child, "KeyR", "BLAR"); |
| SimulateKeyPress(web_contents(), child, "KeyG", "BLARG"); |
| SimulateKeyPress(web_contents(), child, "KeyH", "BLARGH"); |
| ASSERT_TRUE(web_contents()->GetRenderWidgetHostView()->IsKeyboardLocked()); |
| } |
| |
| IN_PROC_BROWSER_TEST_F(KeyboardLockBrowserTest, |
| LockRequestBeforeCrossOriginIFrameIsFullscreen) { |
| // If the main frame trusts the child frame by granting it the allowfullscreen |
| // permission, then we will allow keyboard lock to be activated when the child |
| // frame activates fullscreen. |
| NavigateToTestURL(https_cross_site_frame()); |
| RequestKeyboardLock(FROM_HERE); |
| ASSERT_TRUE(web_contents()->GetKeyboardLockWidget()); |
| ASSERT_FALSE(web_contents()->GetRenderWidgetHostView()->IsKeyboardLocked()); |
| |
| // The third child is cross-domain and has the allowfullscreen attribute set. |
| ASSERT_TRUE( |
| NavigateIframeToURL(web_contents(), kChildIframeName_2, |
| https_test_server()->GetURL(kCrossSiteChildDomain2, |
| kFullscreenFramePath))); |
| RenderFrameHost* main_frame = web_contents()->GetPrimaryMainFrame(); |
| RenderFrameHost* child = ChildFrameAt(main_frame, 2); |
| ASSERT_TRUE(child); |
| |
| ASSERT_TRUE(ExecJs(child, "activateFullscreen()")); |
| |
| ASSERT_EQ(main_frame->GetView()->GetRenderWidgetHost(), |
| web_contents()->GetKeyboardLockWidget()); |
| ASSERT_TRUE(web_contents()->GetRenderWidgetHostView()->IsKeyboardLocked()); |
| } |
| |
| IN_PROC_BROWSER_TEST_F(KeyboardLockBrowserTest, |
| LockRequestWhileCrossOriginIFrameIsFullscreen) { |
| // If the main frame trusts the child frame by granting it the allowfullscreen |
| // permission, then we will allow keyboard lock to be activated when the child |
| // frame activates fullscreen. |
| NavigateToTestURL(https_cross_site_frame()); |
| |
| // The third child is cross-domain and has the allowfullscreen attribute set. |
| ASSERT_TRUE( |
| NavigateIframeToURL(web_contents(), kChildIframeName_2, |
| https_test_server()->GetURL(kCrossSiteChildDomain2, |
| kFullscreenFramePath))); |
| RenderFrameHost* main_frame = web_contents()->GetPrimaryMainFrame(); |
| RenderFrameHost* child = ChildFrameAt(main_frame, 2); |
| ASSERT_TRUE(child); |
| |
| ASSERT_TRUE(ExecJs(child, "activateFullscreen()")); |
| |
| RequestKeyboardLock(FROM_HERE); |
| |
| ASSERT_EQ(main_frame->GetView()->GetRenderWidgetHost(), |
| web_contents()->GetKeyboardLockWidget()); |
| ASSERT_TRUE(web_contents()->GetRenderWidgetHostView()->IsKeyboardLocked()); |
| } |
| |
| IN_PROC_BROWSER_TEST_F(KeyboardLockBrowserTest, |
| LockRequestFailsFromInnerWebContents) { |
| NavigateToTestURL(https_cross_site_frame()); |
| |
| // The first child is a same-origin iframe. |
| RenderFrameHost* main_frame = web_contents()->GetPrimaryMainFrame(); |
| RenderFrameHost* child = ChildFrameAt(main_frame, 0); |
| ASSERT_TRUE(child); |
| |
| WebContents* inner_contents = CreateAndAttachInnerContents(child); |
| inner_contents->SetDelegate(web_contents_delegate()); |
| |
| ASSERT_TRUE( |
| NavigateToURLFromRenderer(inner_contents, https_fullscreen_frame())); |
| |
| ASSERT_EQ(true, EvalJs(inner_contents, kKeyboardLockMethodExistanceCheck)); |
| |
| ASSERT_EQ(false, EvalJs(inner_contents, kKeyboardLockMethodCallWithAllKeys)); |
| |
| // Verify neither inner nor outer WebContents have a pending lock request. |
| WebContentsImpl* inner_contents_impl = |
| static_cast<WebContentsImpl*>(inner_contents); |
| ASSERT_FALSE(inner_contents_impl->GetKeyboardLockWidget()); |
| ASSERT_FALSE( |
| inner_contents_impl->GetRenderWidgetHostView()->IsKeyboardLocked()); |
| ASSERT_FALSE(web_contents()->GetKeyboardLockWidget()); |
| ASSERT_FALSE(web_contents()->GetRenderWidgetHostView()->IsKeyboardLocked()); |
| } |
| |
| IN_PROC_BROWSER_TEST_F(KeyboardLockBrowserTest, |
| InnerContentsFullscreenBehavior) { |
| // TODO(joedow): Added per code review feedback. Need to define the behavior |
| // for KeyboardLock when an attached InnerWebContents goes fullscreen. |
| // Steps: 1. Request keyboard lock for all keys |
| // 2. InnerWebContents request fullscreen |
| // 3. Verify KeyboardLock behavior (should match iframe behavior) |
| } |
| |
| IN_PROC_BROWSER_TEST_F(KeyboardLockBrowserTest, InnerContentsInputBehavior) { |
| // TODO(joedow): Added per code review feedback. Need to define the behavior |
| // for KeyboardLock when an attached InnerWebContents goes fullscreen. |
| // Steps: 1. Request keyboard lock for all keys |
| // 2. Main frame goes fullscreen |
| // 3. Inner web contents is focused |
| // 4. Verify input behavior (should match iframe behavior) |
| } |
| |
| } // namespace content |