Commit 7e2e3d3b authored by Yuichiro Hanada's avatar Yuichiro Hanada Committed by Commit Bot

Add {Show,Hide}VirtualKeyboard to InputMethodManagerInstance.

Moving focus to/from a text field doesn't necessarily show/hide the
virtual keyboard.
For example, a hidden text field is automatically focused when opening
window switcher, but it should not cause the virtual keyboard show up.
This CL adds 2 new methods to ArcInputMethodManagerInstance interface to
control show/hide the virtual keyboard of ARC IMEs.
A caller of HideVirtualKeyboard() will be added later in a separate CL.

Bug: 845079
Test: Open window switcher, but ARC IME doesn't show up.
Change-Id: I538cf826d97a0d3bab49dd64075cde9b55494ac5
Reviewed-on: https://chromium-review.googlesource.com/c/1273395Reviewed-by: default avatarMattias Nissler <mnissler@chromium.org>
Reviewed-by: default avatarYusuke Sato <yusukes@chromium.org>
Commit-Queue: Yuichiro Hanada <yhanada@chromium.org>
Cr-Commit-Position: refs/heads/master@{#598751}
parent 0e16b79d
...@@ -42,6 +42,8 @@ class ArcInputMethodManagerBridge { ...@@ -42,6 +42,8 @@ class ArcInputMethodManagerBridge {
virtual void SendFocus(mojom::InputConnectionPtr connection, virtual void SendFocus(mojom::InputConnectionPtr connection,
mojom::TextInputStatePtr state) = 0; mojom::TextInputStatePtr state) = 0;
virtual void SendUpdateTextInputState(mojom::TextInputStatePtr state) = 0; virtual void SendUpdateTextInputState(mojom::TextInputStatePtr state) = 0;
virtual void SendShowVirtualKeyboard() = 0;
virtual void SendHideVirtualKeyboard() = 0;
}; };
} // namespace arc } // namespace arc
......
...@@ -81,6 +81,30 @@ void ArcInputMethodManagerBridgeImpl::SendUpdateTextInputState( ...@@ -81,6 +81,30 @@ void ArcInputMethodManagerBridgeImpl::SendUpdateTextInputState(
imm_instance->UpdateTextInputState(std::move(state)); imm_instance->UpdateTextInputState(std::move(state));
} }
void ArcInputMethodManagerBridgeImpl::SendShowVirtualKeyboard() {
auto* imm_instance = ARC_GET_INSTANCE_FOR_METHOD(
bridge_service_->input_method_manager(), ShowVirtualKeyboard);
if (!imm_instance)
return;
if (!base::FeatureList::IsEnabled(kEnableInputMethodFeature))
return;
imm_instance->ShowVirtualKeyboard();
}
void ArcInputMethodManagerBridgeImpl::SendHideVirtualKeyboard() {
auto* imm_instance = ARC_GET_INSTANCE_FOR_METHOD(
bridge_service_->input_method_manager(), HideVirtualKeyboard);
if (!imm_instance)
return;
if (!base::FeatureList::IsEnabled(kEnableInputMethodFeature))
return;
imm_instance->HideVirtualKeyboard();
}
void ArcInputMethodManagerBridgeImpl::OnConnectionClosed() { void ArcInputMethodManagerBridgeImpl::OnConnectionClosed() {
delegate_->OnConnectionClosed(); delegate_->OnConnectionClosed();
} }
......
...@@ -34,6 +34,8 @@ class ArcInputMethodManagerBridgeImpl ...@@ -34,6 +34,8 @@ class ArcInputMethodManagerBridgeImpl
void SendFocus(mojom::InputConnectionPtr connection, void SendFocus(mojom::InputConnectionPtr connection,
mojom::TextInputStatePtr state) override; mojom::TextInputStatePtr state) override;
void SendUpdateTextInputState(mojom::TextInputStatePtr state) override; void SendUpdateTextInputState(mojom::TextInputStatePtr state) override;
void SendShowVirtualKeyboard() override;
void SendHideVirtualKeyboard() override;
// ConnectionObserver<mojom::InputMethodManagerInstance> overrides: // ConnectionObserver<mojom::InputMethodManagerInstance> overrides:
void OnConnectionClosed() override; void OnConnectionClosed() override;
......
...@@ -28,6 +28,7 @@ ...@@ -28,6 +28,7 @@
#include "ui/base/ime/chromeos/extension_ime_util.h" #include "ui/base/ime/chromeos/extension_ime_util.h"
#include "ui/base/ime/chromeos/input_method_util.h" #include "ui/base/ime/chromeos/input_method_util.h"
#include "ui/base/ime/ime_bridge.h" #include "ui/base/ime/ime_bridge.h"
#include "ui/base/ime/input_method_observer.h"
#include "ui/keyboard/keyboard_util.h" #include "ui/keyboard/keyboard_util.h"
namespace arc { namespace arc {
...@@ -90,15 +91,16 @@ class ArcInputMethodManagerServiceFactory ...@@ -90,15 +91,16 @@ class ArcInputMethodManagerServiceFactory
} // namespace } // namespace
class ArcInputMethodManagerService::ArcProxyInputMethodObserver class ArcInputMethodManagerService::InputMethodEngineObserver
: public input_method::InputMethodEngineBase::Observer { : public input_method::InputMethodEngineBase::Observer {
public: public:
explicit ArcProxyInputMethodObserver(ArcInputMethodManagerService* owner) explicit InputMethodEngineObserver(ArcInputMethodManagerService* owner)
: owner_(owner) {} : owner_(owner) {}
~ArcProxyInputMethodObserver() override = default; ~InputMethodEngineObserver() override = default;
// input_method::InputMethodEngineBase::Observer overrides: // input_method::InputMethodEngineBase::Observer overrides:
void OnActivate(const std::string& engine_id) override { void OnActivate(const std::string& engine_id) override {
owner_->OnArcImeActivated();
// ash::Shell is not created in the unit tests. // ash::Shell is not created in the unit tests.
if (!ash::Shell::HasInstance()) if (!ash::Shell::HasInstance())
return; return;
...@@ -120,6 +122,7 @@ class ArcInputMethodManagerService::ArcProxyInputMethodObserver ...@@ -120,6 +122,7 @@ class ArcInputMethodManagerService::ArcProxyInputMethodObserver
ui::IMEEngineHandlerInterface::KeyEventDoneCallback key_data) override {} ui::IMEEngineHandlerInterface::KeyEventDoneCallback key_data) override {}
void OnReset(const std::string& engine_id) override {} void OnReset(const std::string& engine_id) override {}
void OnDeactivated(const std::string& engine_id) override { void OnDeactivated(const std::string& engine_id) override {
owner_->OnArcImeDeactivated();
// ash::Shell is not created in the unit tests. // ash::Shell is not created in the unit tests.
if (!ash::Shell::HasInstance()) if (!ash::Shell::HasInstance())
return; return;
...@@ -157,7 +160,30 @@ class ArcInputMethodManagerService::ArcProxyInputMethodObserver ...@@ -157,7 +160,30 @@ class ArcInputMethodManagerService::ArcProxyInputMethodObserver
private: private:
ArcInputMethodManagerService* const owner_; ArcInputMethodManagerService* const owner_;
DISALLOW_COPY_AND_ASSIGN(ArcProxyInputMethodObserver); DISALLOW_COPY_AND_ASSIGN(InputMethodEngineObserver);
};
class ArcInputMethodManagerService::InputMethodObserver
: public ui::InputMethodObserver {
public:
explicit InputMethodObserver(ArcInputMethodManagerService* owner)
: owner_(owner) {}
~InputMethodObserver() override = default;
// ui::InputMethodObserver overrides:
void OnFocus() override {}
void OnBlur() override {}
void OnCaretBoundsChanged(const ui::TextInputClient* client) override {}
void OnTextInputStateChanged(const ui::TextInputClient* client) override {}
void OnInputMethodDestroyed(const ui::InputMethod* input_method) override {}
void OnShowVirtualKeyboardIfEnabled() override {
owner_->imm_bridge_->SendShowVirtualKeyboard();
}
private:
ArcInputMethodManagerService* const owner_;
DISALLOW_COPY_AND_ASSIGN(InputMethodObserver);
}; };
class ArcInputMethodManagerService::TabletModeObserver class ArcInputMethodManagerService::TabletModeObserver
...@@ -203,13 +229,14 @@ ArcInputMethodManagerService::ArcInputMethodManagerService( ...@@ -203,13 +229,14 @@ ArcInputMethodManagerService::ArcInputMethodManagerService(
proxy_ime_extension_id_( proxy_ime_extension_id_(
crx_file::id_util::GenerateId(kArcIMEProxyExtensionName)), crx_file::id_util::GenerateId(kArcIMEProxyExtensionName)),
proxy_ime_engine_(std::make_unique<chromeos::InputMethodEngine>()), proxy_ime_engine_(std::make_unique<chromeos::InputMethodEngine>()),
tablet_mode_observer_(std::make_unique<TabletModeObserver>(this)) { tablet_mode_observer_(std::make_unique<TabletModeObserver>(this)),
input_method_observer_(std::make_unique<InputMethodObserver>(this)) {
auto* imm = chromeos::input_method::InputMethodManager::Get(); auto* imm = chromeos::input_method::InputMethodManager::Get();
imm->AddObserver(this); imm->AddObserver(this);
imm->AddImeMenuObserver(this); imm->AddImeMenuObserver(this);
proxy_ime_engine_->Initialize( proxy_ime_engine_->Initialize(
std::make_unique<ArcProxyInputMethodObserver>(this), std::make_unique<InputMethodEngineObserver>(this),
proxy_ime_extension_id_.c_str(), profile_); proxy_ime_extension_id_.c_str(), profile_);
// TabletModeClient should be already created here because it's created in // TabletModeClient should be already created here because it's created in
...@@ -586,4 +613,18 @@ void ArcInputMethodManagerService::NotifyInputMethodManagerObservers( ...@@ -586,4 +613,18 @@ void ArcInputMethodManagerService::NotifyInputMethodManagerObservers(
manager->NotifyInputMethodExtensionAdded(proxy_ime_extension_id_); manager->NotifyInputMethodExtensionAdded(proxy_ime_extension_id_);
} }
void ArcInputMethodManagerService::OnArcImeActivated() {
ui::InputMethod* input_method =
ui::IMEBridge::Get()->GetInputContextHandler()->GetInputMethod();
if (input_method)
input_method->AddObserver(input_method_observer_.get());
}
void ArcInputMethodManagerService::OnArcImeDeactivated() {
ui::InputMethod* input_method =
ui::IMEBridge::Get()->GetInputContextHandler()->GetInputMethod();
if (input_method)
input_method->RemoveObserver(input_method_observer_.get());
}
} // namespace arc } // namespace arc
...@@ -70,7 +70,8 @@ class ArcInputMethodManagerService ...@@ -70,7 +70,8 @@ class ArcInputMethodManagerService
InputConnectionImpl* GetInputConnectionForTesting(); InputConnectionImpl* GetInputConnectionForTesting();
private: private:
class ArcProxyInputMethodObserver; class InputMethodEngineObserver;
class InputMethodObserver;
class TabletModeObserver; class TabletModeObserver;
void EnableIme(const std::string& ime_id, bool enable); void EnableIme(const std::string& ime_id, bool enable);
...@@ -95,6 +96,10 @@ class ArcInputMethodManagerService ...@@ -95,6 +96,10 @@ class ArcInputMethodManagerService
// Notifies InputMethodManager's observers of possible ARC IME state changes. // Notifies InputMethodManager's observers of possible ARC IME state changes.
void NotifyInputMethodManagerObservers(bool is_tablet_mode); void NotifyInputMethodManagerObservers(bool is_tablet_mode);
// Called by InputMethodEngineObserver.
void OnArcImeActivated();
void OnArcImeDeactivated();
Profile* const profile_; Profile* const profile_;
std::unique_ptr<ArcInputMethodManagerBridge> imm_bridge_; std::unique_ptr<ArcInputMethodManagerBridge> imm_bridge_;
...@@ -110,6 +115,8 @@ class ArcInputMethodManagerService ...@@ -110,6 +115,8 @@ class ArcInputMethodManagerService
std::unique_ptr<TabletModeObserver> tablet_mode_observer_; std::unique_ptr<TabletModeObserver> tablet_mode_observer_;
std::unique_ptr<InputMethodObserver> input_method_observer_;
DISALLOW_COPY_AND_ASSIGN(ArcInputMethodManagerService); DISALLOW_COPY_AND_ASSIGN(ArcInputMethodManagerService);
}; };
......
...@@ -206,11 +206,17 @@ class TestInputMethodManagerBridge : public ArcInputMethodManagerBridge { ...@@ -206,11 +206,17 @@ class TestInputMethodManagerBridge : public ArcInputMethodManagerBridge {
last_text_input_state = state.Clone(); last_text_input_state = state.Clone();
} }
void SendShowVirtualKeyboard() override {
++show_virtual_keyboard_calls_count_;
}
void SendHideVirtualKeyboard() override {}
std::vector<std::tuple<std::string, bool>> enable_ime_calls_; std::vector<std::tuple<std::string, bool>> enable_ime_calls_;
std::vector<std::string> switch_ime_to_calls_; std::vector<std::string> switch_ime_to_calls_;
int focus_calls_count_ = 0; int focus_calls_count_ = 0;
int update_text_input_state_calls_count_ = 0; int update_text_input_state_calls_count_ = 0;
mojom::TextInputStatePtr last_text_input_state; mojom::TextInputStatePtr last_text_input_state;
int show_virtual_keyboard_calls_count_ = 0;
private: private:
DISALLOW_COPY_AND_ASSIGN(TestInputMethodManagerBridge); DISALLOW_COPY_AND_ASSIGN(TestInputMethodManagerBridge);
...@@ -669,14 +675,8 @@ TEST_F(ArcInputMethodManagerServiceTest, FocusAndBlur) { ...@@ -669,14 +675,8 @@ TEST_F(ArcInputMethodManagerServiceTest, FocusAndBlur) {
ASSERT_EQ(1u, imm()->state()->added_input_method_extensions_.size()); ASSERT_EQ(1u, imm()->state()->added_input_method_extensions_.size());
ui::IMEEngineHandlerInterface* engine_handler = ui::IMEEngineHandlerInterface* engine_handler =
std::get<2>(imm()->state()->added_input_method_extensions_.at(0)); std::get<2>(imm()->state()->added_input_method_extensions_.at(0));
// Enable it
ui::IMEBridge::Get()->SetCurrentEngineHandler(engine_handler);
engine_handler->Enable(
chromeos::extension_ime_util::GetComponentIDByInputMethodID(
std::get<1>(imm()->state()->added_input_method_extensions_.at(0))
.at(0)
.id()));
// Set up mock input context.
constexpr int test_context_id = 0; constexpr int test_context_id = 0;
const ui::IMEEngineHandlerInterface::InputContext test_context{ const ui::IMEEngineHandlerInterface::InputContext test_context{
test_context_id, test_context_id,
...@@ -687,8 +687,16 @@ TEST_F(ArcInputMethodManagerServiceTest, FocusAndBlur) { ...@@ -687,8 +687,16 @@ TEST_F(ArcInputMethodManagerServiceTest, FocusAndBlur) {
true /* should_do_learning */}; true /* should_do_learning */};
ui::MockInputMethod mock_input_method(nullptr); ui::MockInputMethod mock_input_method(nullptr);
TestIMEInputContextHandler test_context_handler(&mock_input_method); TestIMEInputContextHandler test_context_handler(&mock_input_method);
ui::DummyTextInputClient dummy_text_input_client; ui::DummyTextInputClient dummy_text_input_client(ui::TEXT_INPUT_TYPE_TEXT);
ui::IMEBridge::Get()->SetInputContextHandler(&test_context_handler); ui::IMEBridge::Get()->SetInputContextHandler(&test_context_handler);
// Enable the ARC IME.
ui::IMEBridge::Get()->SetCurrentEngineHandler(engine_handler);
engine_handler->Enable(
chromeos::extension_ime_util::GetComponentIDByInputMethodID(
std::get<1>(imm()->state()->added_input_method_extensions_.at(0))
.at(0)
.id()));
mock_input_method.SetFocusedTextInputClient(&dummy_text_input_client); mock_input_method.SetFocusedTextInputClient(&dummy_text_input_client);
ASSERT_EQ(0, bridge()->focus_calls_count_); ASSERT_EQ(0, bridge()->focus_calls_count_);
...@@ -737,14 +745,8 @@ TEST_F(ArcInputMethodManagerServiceTest, IMEOperations) { ...@@ -737,14 +745,8 @@ TEST_F(ArcInputMethodManagerServiceTest, IMEOperations) {
ASSERT_EQ(1u, imm()->state()->added_input_method_extensions_.size()); ASSERT_EQ(1u, imm()->state()->added_input_method_extensions_.size());
ui::IMEEngineHandlerInterface* engine_handler = ui::IMEEngineHandlerInterface* engine_handler =
std::get<2>(imm()->state()->added_input_method_extensions_.at(0)); std::get<2>(imm()->state()->added_input_method_extensions_.at(0));
// Enable it
ui::IMEBridge::Get()->SetCurrentEngineHandler(engine_handler);
engine_handler->Enable(
chromeos::extension_ime_util::GetComponentIDByInputMethodID(
std::get<1>(imm()->state()->added_input_method_extensions_.at(0))
.at(0)
.id()));
// Set up mock input context.
constexpr int test_context_id = 0; constexpr int test_context_id = 0;
const ui::IMEEngineHandlerInterface::InputContext test_context{ const ui::IMEEngineHandlerInterface::InputContext test_context{
test_context_id, test_context_id,
...@@ -757,6 +759,14 @@ TEST_F(ArcInputMethodManagerServiceTest, IMEOperations) { ...@@ -757,6 +759,14 @@ TEST_F(ArcInputMethodManagerServiceTest, IMEOperations) {
TestIMEInputContextHandler test_context_handler(&mock_input_method); TestIMEInputContextHandler test_context_handler(&mock_input_method);
ui::DummyTextInputClient dummy_text_input_client(ui::TEXT_INPUT_TYPE_TEXT); ui::DummyTextInputClient dummy_text_input_client(ui::TEXT_INPUT_TYPE_TEXT);
ui::IMEBridge::Get()->SetInputContextHandler(&test_context_handler); ui::IMEBridge::Get()->SetInputContextHandler(&test_context_handler);
// Enable the ARC IME.
ui::IMEBridge::Get()->SetCurrentEngineHandler(engine_handler);
engine_handler->Enable(
chromeos::extension_ime_util::GetComponentIDByInputMethodID(
std::get<1>(imm()->state()->added_input_method_extensions_.at(0))
.at(0)
.id()));
mock_input_method.SetFocusedTextInputClient(&dummy_text_input_client); mock_input_method.SetFocusedTextInputClient(&dummy_text_input_client);
engine_handler->FocusIn(test_context); engine_handler->FocusIn(test_context);
...@@ -880,4 +890,60 @@ TEST_F(ArcInputMethodManagerServiceTest, DisableFallbackVirtualKeyboard) { ...@@ -880,4 +890,60 @@ TEST_F(ArcInputMethodManagerServiceTest, DisableFallbackVirtualKeyboard) {
EXPECT_TRUE(keyboard::IsKeyboardEnabled()); EXPECT_TRUE(keyboard::IsKeyboardEnabled());
} }
TEST_F(ArcInputMethodManagerServiceTest, ShowVirtualKeyboard) {
base::test::ScopedFeatureList feature;
feature.InitAndEnableFeature(kEnableInputMethodFeature);
ToggleTabletMode(true);
// Adding one ARC IME.
{
const std::string android_ime_id = "test.arc.ime";
const std::string display_name = "DisplayName";
const std::string settings_url = "url_to_settings";
mojom::ImeInfoPtr info = mojom::ImeInfo::New();
info->ime_id = android_ime_id;
info->display_name = display_name;
info->enabled = false;
info->settings_url = settings_url;
std::vector<mojom::ImeInfoPtr> info_array;
info_array.emplace_back(std::move(info));
service()->OnImeInfoChanged(std::move(info_array));
}
// The proxy IME engine should be added.
ASSERT_EQ(1u, imm()->state()->added_input_method_extensions_.size());
ui::IMEEngineHandlerInterface* engine_handler =
std::get<2>(imm()->state()->added_input_method_extensions_.at(0));
// Set up mock input context.
constexpr int test_context_id = 0;
const ui::IMEEngineHandlerInterface::InputContext test_context{
test_context_id,
ui::TEXT_INPUT_TYPE_TEXT,
ui::TEXT_INPUT_MODE_DEFAULT,
0 /* flags */,
ui::TextInputClient::FOCUS_REASON_MOUSE,
true /* should_do_learning */};
ui::MockInputMethod mock_input_method(nullptr);
TestIMEInputContextHandler test_context_handler(&mock_input_method);
ui::DummyTextInputClient dummy_text_input_client(ui::TEXT_INPUT_TYPE_TEXT);
ui::IMEBridge::Get()->SetInputContextHandler(&test_context_handler);
// Enable the ARC IME.
ui::IMEBridge::Get()->SetCurrentEngineHandler(engine_handler);
engine_handler->Enable(
chromeos::extension_ime_util::GetComponentIDByInputMethodID(
std::get<1>(imm()->state()->added_input_method_extensions_.at(0))
.at(0)
.id()));
mock_input_method.SetFocusedTextInputClient(&dummy_text_input_client);
EXPECT_EQ(0, bridge()->show_virtual_keyboard_calls_count_);
mock_input_method.ShowVirtualKeyboardIfEnabled();
EXPECT_EQ(1, bridge()->show_virtual_keyboard_calls_count_);
ui::IMEBridge::Get()->SetInputContextHandler(nullptr);
ui::IMEBridge::Get()->SetCurrentEngineHandler(nullptr);
}
} // namespace arc } // namespace arc
...@@ -2,7 +2,7 @@ ...@@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style license that can be // Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file. // found in the LICENSE file.
// Next MinVersion: 4 // Next MinVersion: 5
module arc.mojom; module arc.mojom;
...@@ -104,7 +104,7 @@ interface InputMethodManagerHost { ...@@ -104,7 +104,7 @@ interface InputMethodManagerHost {
// This interface provides methods to control Android's InputMethodManager. // This interface provides methods to control Android's InputMethodManager.
// //
// Next method ID: 5 // Next method ID: 7
interface InputMethodManagerInstance { interface InputMethodManagerInstance {
// Establishes full-duplex communication with the host. // Establishes full-duplex communication with the host.
Init@0(InputMethodManagerHost host_ptr) => (); Init@0(InputMethodManagerHost host_ptr) => ();
...@@ -123,4 +123,10 @@ interface InputMethodManagerInstance { ...@@ -123,4 +123,10 @@ interface InputMethodManagerInstance {
// Sends the latest TextInputState of the active text field. // Sends the latest TextInputState of the active text field.
[MinVersion=2] UpdateTextInputState@4(TextInputState state); [MinVersion=2] UpdateTextInputState@4(TextInputState state);
// Requests the active IME to show virtual keyboard.
[MinVersion=4] ShowVirtualKeyboard@5();
// Requests the active IME to hide virtual keyboard.
[MinVersion=4] HideVirtualKeyboard@6();
}; };
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment