| // Copyright 2024 The Chromium Authors |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #include "ash/constants/ash_features.h" |
| #include "ash/constants/ash_pref_names.h" |
| #include "base/test/scoped_feature_list.h" |
| #include "base/test/scoped_run_loop_timeout.h" |
| #include "build/build_config.h" |
| #include "chrome/browser/ash/accessibility/accessibility_manager.h" |
| #include "chrome/browser/ash/accessibility/magnification_manager.h" |
| #include "chrome/browser/ash/accessibility/magnifier_type.h" |
| #include "chrome/browser/policy/policy_test_utils.h" |
| #include "chrome/browser/ui/ash/keyboard/chrome_keyboard_controller_client.h" |
| #include "chrome/browser/ui/browser.h" |
| #include "components/policy/core/common/policy_map.h" |
| #include "components/policy/policy_constants.h" |
| #include "components/prefs/pref_service.h" |
| #include "content/public/test/browser_test.h" |
| #include "ui/aura/window.h" |
| #include "ui/aura/window_tree_host.h" |
| #include "ui/base/ime/fake_text_input_client.h" |
| #include "ui/base/ime/input_method.h" |
| |
| namespace policy { |
| namespace { |
| |
| #if BUILDFLAG(GOOGLE_CHROME_BRANDING) |
| |
| ChromeKeyboardControllerClient* GetEnabledKeyboardClient() { |
| auto* client = ChromeKeyboardControllerClient::Get(); |
| if (client != nullptr) { |
| client->SetEnableFlag(keyboard::KeyboardEnableFlag::kTouchEnabled); |
| } |
| return client; |
| } |
| |
| ui::InputMethod* GetInputMethod(ChromeKeyboardControllerClient* client) { |
| aura::Window* root_window = client->GetKeyboardWindow()->GetRootWindow(); |
| return root_window != nullptr ? root_window->GetHost()->GetInputMethod() |
| : nullptr; |
| } |
| |
| void Wait(base::TimeDelta timeout) { |
| base::RunLoop run_loop; |
| base::OneShotTimer timer; |
| timer.Start(FROM_HERE, timeout, run_loop.QuitClosure()); |
| run_loop.Run(); |
| timer.Stop(); |
| } |
| |
| ui::FakeTextInputClient::Options WebTextFieldOptions() { |
| return { |
| .type = ui::TEXT_INPUT_TYPE_TEXT, |
| .mode = ui::TEXT_INPUT_MODE_TEXT, |
| .flags = ui::TEXT_INPUT_FLAG_SPELLCHECK_ON, |
| }; |
| } |
| |
| class KeyboardVisibilityWaiter |
| : public ChromeKeyboardControllerClient::Observer { |
| public: |
| explicit KeyboardVisibilityWaiter(ChromeKeyboardControllerClient* client, |
| bool visible) |
| : visible_(visible) { |
| observer_.Observe(client); |
| } |
| KeyboardVisibilityWaiter(const KeyboardVisibilityWaiter&) = delete; |
| KeyboardVisibilityWaiter& operator=(const KeyboardVisibilityWaiter&) = delete; |
| ~KeyboardVisibilityWaiter() override = default; |
| |
| void Wait() { |
| if (observer_.GetSource()->is_keyboard_visible() != visible_) { |
| run_loop_.Run(); |
| } |
| } |
| |
| // ChromeKeyboardControllerClient::Observer |
| void OnKeyboardVisibilityChanged(bool visible) override { |
| if (visible == visible_) { |
| run_loop_.Quit(); |
| } |
| } |
| |
| private: |
| bool visible_; |
| base::ScopedObservation<ChromeKeyboardControllerClient, |
| ChromeKeyboardControllerClient::Observer> |
| observer_{this}; |
| base::RunLoop run_loop_; |
| }; |
| |
| void WaitUntilKeyboardShown(ChromeKeyboardControllerClient* client) { |
| KeyboardVisibilityWaiter(client, true).Wait(); |
| } |
| |
| void WaitUntilKeyboardHidden(ChromeKeyboardControllerClient* client) { |
| KeyboardVisibilityWaiter(client, false).Wait(); |
| } |
| |
| #endif |
| |
| } // namespace |
| |
| #if BUILDFLAG(GOOGLE_CHROME_BRANDING) |
| |
| class VirtualKeyboardPolicyTest : public PolicyTest {}; |
| |
| IN_PROC_BROWSER_TEST_F(VirtualKeyboardPolicyTest, |
| VirtualKeyboardSmartVisibilityEnabledDefault) { |
| auto* keyboard_client = GetEnabledKeyboardClient(); |
| ASSERT_TRUE(keyboard_client); |
| ui::InputMethod* input_method = GetInputMethod(keyboard_client); |
| ASSERT_TRUE(input_method); |
| ui::FakeTextInputClient text_client(input_method, WebTextFieldOptions()); |
| |
| // Showing the virtual keyboard, losing focus, then focusing again should show |
| // the virtual keyboard again. |
| text_client.Focus(); |
| input_method->SetVirtualKeyboardVisibilityIfEnabled(true); |
| WaitUntilKeyboardShown(keyboard_client); |
| text_client.Blur(); |
| WaitUntilKeyboardHidden(keyboard_client); |
| text_client.Focus(); |
| WaitUntilKeyboardShown(keyboard_client); |
| } |
| |
| IN_PROC_BROWSER_TEST_F(VirtualKeyboardPolicyTest, |
| VirtualKeyboardSmartVisibilityEnabledEnabled) { |
| auto* keyboard_client = GetEnabledKeyboardClient(); |
| ASSERT_TRUE(keyboard_client); |
| ui::InputMethod* input_method = GetInputMethod(keyboard_client); |
| ASSERT_TRUE(input_method); |
| ui::FakeTextInputClient text_client(input_method, WebTextFieldOptions()); |
| |
| PolicyMap policies; |
| policies.Set(key::kVirtualKeyboardSmartVisibilityEnabled, |
| POLICY_LEVEL_MANDATORY, POLICY_SCOPE_USER, POLICY_SOURCE_CLOUD, |
| base::Value(true), nullptr); |
| UpdateProviderPolicy(policies); |
| |
| // Showing the virtual keyboard, losing focus, then focusing again should show |
| // the virtual keyboard again. |
| text_client.Focus(); |
| input_method->SetVirtualKeyboardVisibilityIfEnabled(true); |
| WaitUntilKeyboardShown(keyboard_client); |
| text_client.Blur(); |
| WaitUntilKeyboardHidden(keyboard_client); |
| text_client.Focus(); |
| WaitUntilKeyboardShown(keyboard_client); |
| } |
| |
| IN_PROC_BROWSER_TEST_F(VirtualKeyboardPolicyTest, |
| VirtualKeyboardSmartVisibilityEnabledDisabled) { |
| auto* keyboard_client = GetEnabledKeyboardClient(); |
| ASSERT_TRUE(keyboard_client); |
| ui::InputMethod* input_method = GetInputMethod(keyboard_client); |
| ASSERT_TRUE(input_method); |
| ui::FakeTextInputClient text_client(input_method, WebTextFieldOptions()); |
| |
| PolicyMap policies; |
| policies.Set(key::kVirtualKeyboardSmartVisibilityEnabled, |
| POLICY_LEVEL_MANDATORY, POLICY_SCOPE_USER, POLICY_SOURCE_CLOUD, |
| base::Value(false), nullptr); |
| UpdateProviderPolicy(policies); |
| |
| // Showing the virtual keyboard, losing focus, then focusing again should keep |
| // the virtual keyboard hidden. |
| text_client.Focus(); |
| input_method->SetVirtualKeyboardVisibilityIfEnabled(true); |
| WaitUntilKeyboardShown(keyboard_client); |
| text_client.Blur(); |
| WaitUntilKeyboardHidden(keyboard_client); |
| text_client.Focus(); |
| Wait(base::Seconds(1)); |
| EXPECT_FALSE(keyboard_client->is_keyboard_visible()); |
| } |
| |
| #endif |
| |
| } // namespace policy |