Commit 4808e690 authored by Yuichiro Hanada's avatar Yuichiro Hanada Committed by Commit Bot

Implement ArcInputMethodManagerService::SwitchImeTo().

This CL adds a new method, |SwitchImeTo()|, to
ArcInputMethodManagerService.
ArcInputMethodManagerService observes the change of the active IME in
Chrome OS and send the change to Arc container to synchronize the state
between Chrome OS's InputMethodManager and Arc's InputMethodManager.

Bug: 845079
Test: unit_tests
Change-Id: Ib76795c9c768504a50ec3c4683c5ace6801aaf1d
Reviewed-on: https://chromium-review.googlesource.com/1102230Reviewed-by: default avatarYusuke Sato <yusukes@chromium.org>
Commit-Queue: Yuichiro Hanada <yhanada@chromium.org>
Cr-Commit-Position: refs/heads/master@{#567941}
parent df0dd8fc
...@@ -14,6 +14,12 @@ namespace arc { ...@@ -14,6 +14,12 @@ namespace arc {
namespace { namespace {
// The Android IME id of the pre-installed IME to proxy Chrome OS IME's actions
// to inside the container.
// Please refer to ArcImeService for the implementation details.
constexpr char kChromeOSIMEIdInArcContainer[] =
"org.chromium.arc.ime/.ArcInputMethodService";
// Singleton factory for ArcInputMethodManagerService // Singleton factory for ArcInputMethodManagerService
class ArcInputMethodManagerServiceFactory class ArcInputMethodManagerServiceFactory
: public internal::ArcBrowserContextKeyedServiceFactoryBase< : public internal::ArcBrowserContextKeyedServiceFactoryBase<
...@@ -55,9 +61,17 @@ ArcInputMethodManagerService::ArcInputMethodManagerService( ...@@ -55,9 +61,17 @@ ArcInputMethodManagerService::ArcInputMethodManagerService(
ArcBridgeService* bridge_service) ArcBridgeService* bridge_service)
: imm_bridge_( : imm_bridge_(
std::make_unique<ArcInputMethodManagerBridgeImpl>(this, std::make_unique<ArcInputMethodManagerBridgeImpl>(this,
bridge_service)) {} bridge_service)) {
auto* imm = chromeos::input_method::InputMethodManager::Get();
imm->AddObserver(this);
imm->AddImeMenuObserver(this);
}
ArcInputMethodManagerService::~ArcInputMethodManagerService() = default; ArcInputMethodManagerService::~ArcInputMethodManagerService() {
auto* imm = chromeos::input_method::InputMethodManager::Get();
imm->RemoveImeMenuObserver(this);
imm->RemoveObserver(this);
}
void ArcInputMethodManagerService::SetInputMethodManagerBridgeForTesting( void ArcInputMethodManagerService::SetInputMethodManagerBridgeForTesting(
std::unique_ptr<ArcInputMethodManagerBridge> test_bridge) { std::unique_ptr<ArcInputMethodManagerBridge> test_bridge) {
...@@ -104,6 +118,16 @@ void ArcInputMethodManagerService::ImeMenuListChanged() { ...@@ -104,6 +118,16 @@ void ArcInputMethodManagerService::ImeMenuListChanged() {
active_arc_ime_ids_.swap(new_arc_active_ime_ids); active_arc_ime_ids_.swap(new_arc_active_ime_ids);
} }
void ArcInputMethodManagerService::InputMethodChanged(
chromeos::input_method::InputMethodManager* manager,
Profile* profile,
bool /* show_message */) {
auto state = manager->GetActiveIMEState();
if (!state)
return;
SwitchImeTo(state->GetCurrentInputMethod().id());
}
void ArcInputMethodManagerService::EnableIme(const std::string& ime_id, void ArcInputMethodManagerService::EnableIme(const std::string& ime_id,
bool enable) { bool enable) {
auto component_id = auto component_id =
...@@ -122,4 +146,23 @@ void ArcInputMethodManagerService::EnableIme(const std::string& ime_id, ...@@ -122,4 +146,23 @@ void ArcInputMethodManagerService::EnableIme(const std::string& ime_id,
ime_id, enable)); ime_id, enable));
} }
void ArcInputMethodManagerService::SwitchImeTo(const std::string& ime_id) {
using namespace chromeos::extension_ime_util;
std::string component_id = GetComponentIDByInputMethodID(ime_id);
if (!IsArcIME(ime_id))
component_id = kChromeOSIMEIdInArcContainer;
imm_bridge_->SendSwitchImeTo(
component_id, base::BindOnce(
[](const std::string& ime_id,
const std::string& component_id, bool success) {
if (!success) {
LOG(ERROR) << "Switch the active IME to \""
<< ime_id << "\"(component_id=\""
<< component_id << "\") failed";
}
},
ime_id, component_id));
}
} // namespace arc } // namespace arc
...@@ -25,7 +25,8 @@ class ArcBridgeService; ...@@ -25,7 +25,8 @@ class ArcBridgeService;
class ArcInputMethodManagerService class ArcInputMethodManagerService
: public KeyedService, : public KeyedService,
public ArcInputMethodManagerBridge::Delegate, public ArcInputMethodManagerBridge::Delegate,
public chromeos::input_method::InputMethodManager::ImeMenuObserver { public chromeos::input_method::InputMethodManager::ImeMenuObserver,
public chromeos::input_method::InputMethodManager::Observer {
public: public:
// Returns the instance for the given BrowserContext, or nullptr if the // Returns the instance for the given BrowserContext, or nullptr if the
// browser |context| is not allowed to use ARC. // browser |context| is not allowed to use ARC.
...@@ -55,8 +56,14 @@ class ArcInputMethodManagerService ...@@ -55,8 +56,14 @@ class ArcInputMethodManagerService
const std::vector<chromeos::input_method::InputMethodManager::MenuItem>& const std::vector<chromeos::input_method::InputMethodManager::MenuItem>&
items) override {} items) override {}
// chromeos::input_method::InputMethodManager::Observer overrides:
void InputMethodChanged(chromeos::input_method::InputMethodManager* manager,
Profile* profile,
bool show_message) override;
private: private:
void EnableIme(const std::string& ime_id, bool enable); void EnableIme(const std::string& ime_id, bool enable);
void SwitchImeTo(const std::string& ime_id);
std::unique_ptr<ArcInputMethodManagerBridge> imm_bridge_; std::unique_ptr<ArcInputMethodManagerBridge> imm_bridge_;
std::set<std::string> active_arc_ime_ids_; std::set<std::string> active_arc_ime_ids_;
......
...@@ -37,6 +37,14 @@ class TestInputMethodManager : public im::MockInputMethodManager { ...@@ -37,6 +37,14 @@ class TestInputMethodManager : public im::MockInputMethodManager {
return active_input_method_ids_; return active_input_method_ids_;
} }
im::InputMethodDescriptor GetCurrentInputMethod() const override {
im::InputMethodDescriptor descriptor(
active_ime_id_, "", "", std::vector<std::string>(),
std::vector<std::string>(), false /* is_login_keyboard */, GURL(),
GURL());
return descriptor;
}
void AddActiveInputMethodId(const std::string& ime_id) { void AddActiveInputMethodId(const std::string& ime_id) {
if (!std::count(active_input_method_ids_.begin(), if (!std::count(active_input_method_ids_.begin(),
active_input_method_ids_.end(), ime_id)) { active_input_method_ids_.end(), ime_id)) {
...@@ -50,12 +58,17 @@ class TestInputMethodManager : public im::MockInputMethodManager { ...@@ -50,12 +58,17 @@ class TestInputMethodManager : public im::MockInputMethodManager {
[&ime_id](const std::string& id) { return id == ime_id; })); [&ime_id](const std::string& id) { return id == ime_id; }));
} }
void SetActiveInputMethod(const std::string& ime_id) {
active_ime_id_ = ime_id;
}
protected: protected:
friend base::RefCounted<InputMethodManager::State>; friend base::RefCounted<InputMethodManager::State>;
~TestState() override = default; ~TestState() override = default;
private: private:
std::vector<std::string> active_input_method_ids_; std::vector<std::string> active_input_method_ids_;
std::string active_ime_id_ = "";
}; };
TestInputMethodManager() { TestInputMethodManager() {
...@@ -88,10 +101,12 @@ class TestInputMethodManagerBridge : public ArcInputMethodManagerBridge { ...@@ -88,10 +101,12 @@ class TestInputMethodManagerBridge : public ArcInputMethodManagerBridge {
} }
void SendSwitchImeTo(const std::string& ime_id, void SendSwitchImeTo(const std::string& ime_id,
SwitchImeToCallback callback) override { SwitchImeToCallback callback) override {
switch_ime_to_calls_.push_back(ime_id);
std::move(callback).Run(true); std::move(callback).Run(true);
} }
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_;
private: private:
DISALLOW_COPY_AND_ASSIGN(TestInputMethodManagerBridge); DISALLOW_COPY_AND_ASSIGN(TestInputMethodManagerBridge);
...@@ -100,11 +115,8 @@ class TestInputMethodManagerBridge : public ArcInputMethodManagerBridge { ...@@ -100,11 +115,8 @@ class TestInputMethodManagerBridge : public ArcInputMethodManagerBridge {
class ArcInputMethodManagerServiceTest : public testing::Test { class ArcInputMethodManagerServiceTest : public testing::Test {
protected: protected:
ArcInputMethodManagerServiceTest() ArcInputMethodManagerServiceTest()
: arc_service_manager_(std::make_unique<ArcServiceManager>()), : arc_service_manager_(std::make_unique<ArcServiceManager>()) {}
context_(std::make_unique<TestBrowserContext>()), ~ArcInputMethodManagerServiceTest() override {}
service_(ArcInputMethodManagerService::GetForBrowserContextForTesting(
context_.get())) {}
~ArcInputMethodManagerServiceTest() override { service_->Shutdown(); }
ArcInputMethodManagerService* service() { return service_; } ArcInputMethodManagerService* service() { return service_; }
...@@ -116,6 +128,12 @@ class ArcInputMethodManagerServiceTest : public testing::Test { ...@@ -116,6 +128,12 @@ class ArcInputMethodManagerServiceTest : public testing::Test {
input_method_manager_ = new TestInputMethodManager(); input_method_manager_ = new TestInputMethodManager();
chromeos::input_method::InputMethodManager::Initialize( chromeos::input_method::InputMethodManager::Initialize(
input_method_manager_); input_method_manager_);
context_ = std::make_unique<TestBrowserContext>();
service_ = ArcInputMethodManagerService::GetForBrowserContextForTesting(
context_.get());
test_bridge_ = new TestInputMethodManagerBridge(); test_bridge_ = new TestInputMethodManagerBridge();
service_->SetInputMethodManagerBridgeForTesting( service_->SetInputMethodManagerBridgeForTesting(
base::WrapUnique(test_bridge_)); base::WrapUnique(test_bridge_));
...@@ -123,6 +141,10 @@ class ArcInputMethodManagerServiceTest : public testing::Test { ...@@ -123,6 +141,10 @@ class ArcInputMethodManagerServiceTest : public testing::Test {
void TearDown() override { void TearDown() override {
test_bridge_ = nullptr; test_bridge_ = nullptr;
service_->Shutdown();
context_.reset(nullptr);
chromeos::input_method::InputMethodManager::Shutdown(); chromeos::input_method::InputMethodManager::Shutdown();
} }
...@@ -133,7 +155,7 @@ class ArcInputMethodManagerServiceTest : public testing::Test { ...@@ -133,7 +155,7 @@ class ArcInputMethodManagerServiceTest : public testing::Test {
TestInputMethodManager* input_method_manager_ = nullptr; TestInputMethodManager* input_method_manager_ = nullptr;
TestInputMethodManagerBridge* test_bridge_ = nullptr; // Owned by |service_| TestInputMethodManagerBridge* test_bridge_ = nullptr; // Owned by |service_|
ArcInputMethodManagerService* const service_ = nullptr; ArcInputMethodManagerService* service_ = nullptr;
DISALLOW_COPY_AND_ASSIGN(ArcInputMethodManagerServiceTest); DISALLOW_COPY_AND_ASSIGN(ArcInputMethodManagerServiceTest);
}; };
...@@ -195,4 +217,44 @@ TEST_F(ArcInputMethodManagerServiceTest, EnableIme) { ...@@ -195,4 +217,44 @@ TEST_F(ArcInputMethodManagerServiceTest, EnableIme) {
EXPECT_EQ(2u, bridge()->enable_ime_calls_.size()); EXPECT_EQ(2u, bridge()->enable_ime_calls_.size());
} }
TEST_F(ArcInputMethodManagerServiceTest, SwitchImeTo) {
using namespace chromeos::extension_ime_util;
using crx_file::id_util::GenerateId;
const std::string arc_ime_service_id =
"org.chromium.arc.ime/.ArcInputMethodService";
base::test::ScopedFeatureList feature;
feature.InitAndEnableFeature(kEnableInputMethodFeature);
ASSERT_EQ(0u, bridge()->switch_ime_to_calls_.size());
const std::string extension_ime_id =
GetInputMethodID(GenerateId("test.extension.ime"), "us");
const std::string component_extension_ime_id = GetComponentInputMethodID(
GenerateId("test.component.extension.ime"), "us");
const std::string arc_ime_id = GetArcInputMethodID(GenerateId("test.arc.ime"),
"ime.id.in.arc.container");
// Set active input method to the extension ime.
imm()->state()->SetActiveInputMethod(extension_ime_id);
service()->InputMethodChanged(imm(), nullptr, false /* show_message */);
// ArcImeService should be selected.
ASSERT_EQ(1u, bridge()->switch_ime_to_calls_.size());
EXPECT_EQ(arc_ime_service_id, bridge()->switch_ime_to_calls_[0]);
// Set active input method to the component extension ime.
imm()->state()->SetActiveInputMethod(component_extension_ime_id);
service()->InputMethodChanged(imm(), nullptr, false /* show_message */);
// ArcImeService should be selected.
ASSERT_EQ(2u, bridge()->switch_ime_to_calls_.size());
EXPECT_EQ(arc_ime_service_id, bridge()->switch_ime_to_calls_[1]);
// Set active input method to the arc ime.
imm()->state()->SetActiveInputMethod(arc_ime_id);
service()->InputMethodChanged(imm(), nullptr, false /* show_message */);
ASSERT_EQ(3u, bridge()->switch_ime_to_calls_.size());
EXPECT_EQ("ime.id.in.arc.container", bridge()->switch_ime_to_calls_[2]);
}
} // namespace arc } // namespace arc
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