blob: ec7414f9fa22cdbd8f27e15f6315301157d479ff [file] [log] [blame]
// Copyright (c) 2012 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 "chrome/browser/chromeos/input_method/input_method_manager_impl.h"
#include <stddef.h>
#include <algorithm>
#include <memory>
#include <utility>
#include "base/bind.h"
#include "base/bind_helpers.h"
#include "base/compiler_specific.h"
#include "base/logging.h"
#include "base/macros.h"
#include "base/run_loop.h"
#include "base/test/scoped_task_environment.h"
#include "chrome/browser/chromeos/input_method/mock_candidate_window_controller.h"
#include "chrome/browser/chromeos/input_method/mock_input_method_engine.h"
#include "chrome/browser/profiles/profile_manager.h"
#include "chrome/browser/ui/ash/ime_controller_client.h"
#include "chrome/browser/ui/ash/keyboard/chrome_keyboard_controller_client_test_helper.h"
#include "chrome/browser/ui/ash/test_ime_controller.h"
#include "chrome/test/base/browser_with_test_window_test.h"
#include "chrome/test/base/testing_profile.h"
#include "chrome/test/base/testing_profile_manager.h"
#include "content/public/test/test_service_manager_context.h"
#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "ui/base/ime/chromeos/extension_ime_util.h"
#include "ui/base/ime/chromeos/fake_ime_keyboard.h"
#include "ui/base/ime/chromeos/fake_input_method_delegate.h"
#include "ui/base/ime/chromeos/mock_component_extension_ime_manager_delegate.h"
#include "ui/base/ime/chromeos/mock_ime_engine_handler.h"
#include "ui/base/ime/ime_bridge.h"
#include "ui/base/ime/input_method_initializer.h"
namespace chromeos {
namespace input_method {
namespace {
const char kNaclMozcUsId[] = "nacl_mozc_us";
const char kNaclMozcJpId[] = "nacl_mozc_jp";
const char kExt2Engine1Id[] = "ext2_engine1-t-i0-engine_id";
const char kExt2Engine2Id[] = "ext2_engine2-t-i0-engine_id";
const char kPinyinImeId[] = "zh-t-i0-pinyin";
const char kExtensionId1[] = "00000000000000000000000000000000";
const char kExtensionId2[] = "11111111111111111111111111111111";
// Returns true if |descriptors| contain |target|.
bool Contain(const InputMethodDescriptors& descriptors,
const InputMethodDescriptor& target) {
for (size_t i = 0; i < descriptors.size(); ++i) {
if (descriptors[i].id() == target.id())
return true;
}
return false;
}
std::string ImeIdFromEngineId(const std::string& id) {
return extension_ime_util::GetInputMethodIDByEngineID(id);
}
class TestObserver : public InputMethodManager::Observer,
public ui::ime::InputMethodMenuManager::Observer {
public:
TestObserver()
: input_method_changed_count_(0),
input_method_extension_added_count_(0),
input_method_extension_removed_count_(0),
input_method_menu_item_changed_count_(0),
last_show_message_(false) {}
~TestObserver() override {}
void InputMethodChanged(InputMethodManager* manager,
Profile* /* profile */,
bool show_message) override {
++input_method_changed_count_;
last_show_message_ = show_message;
}
void OnInputMethodExtensionAdded(const std::string& id) override {
++input_method_extension_added_count_;
}
void OnInputMethodExtensionRemoved(const std::string& id) override {
++input_method_extension_removed_count_;
}
void InputMethodMenuItemChanged(
ui::ime::InputMethodMenuManager* manager) override {
++input_method_menu_item_changed_count_;
}
int input_method_changed_count_;
int input_method_extension_added_count_;
int input_method_extension_removed_count_;
int input_method_menu_item_changed_count_;
bool last_show_message_;
private:
DISALLOW_COPY_AND_ASSIGN(TestObserver);
};
class TestCandidateWindowObserver
: public InputMethodManager::CandidateWindowObserver {
public:
TestCandidateWindowObserver()
: candidate_window_opened_count_(0),
candidate_window_closed_count_(0) {
}
~TestCandidateWindowObserver() override {}
void CandidateWindowOpened(InputMethodManager* manager) override {
++candidate_window_opened_count_;
}
void CandidateWindowClosed(InputMethodManager* manager) override {
++candidate_window_closed_count_;
}
int candidate_window_opened_count_;
int candidate_window_closed_count_;
private:
DISALLOW_COPY_AND_ASSIGN(TestCandidateWindowObserver);
};
} // namespace
class InputMethodManagerImplTest : public BrowserWithTestWindowTest {
public:
InputMethodManagerImplTest()
: delegate_(nullptr),
candidate_window_controller_(nullptr),
keyboard_(nullptr) {
chrome_keyboard_controller_client_test_helper_ =
ChromeKeyboardControllerClientTestHelper::InitializeWithFake();
}
~InputMethodManagerImplTest() override {
chrome_keyboard_controller_client_test_helper_.reset();
}
void SetUp() override {
ui::InitializeInputMethodForTesting();
delegate_ = new FakeInputMethodDelegate();
manager_.reset(new InputMethodManagerImpl(
std::unique_ptr<InputMethodDelegate>(delegate_), false));
manager_->GetInputMethodUtil()->UpdateHardwareLayoutCache();
candidate_window_controller_ = new MockCandidateWindowController;
manager_->SetCandidateWindowControllerForTesting(
candidate_window_controller_);
keyboard_ = new FakeImeKeyboard;
manager_->SetImeKeyboardForTesting(keyboard_);
mock_engine_handler_.reset(new MockInputMethodEngine());
ui::IMEBridge::Initialize();
ui::IMEBridge::Get()->SetCurrentEngineHandler(mock_engine_handler_.get());
menu_manager_ = ui::ime::InputMethodMenuManager::GetInstance();
InitImeList();
BrowserWithTestWindowTest::SetUp();
}
void TearDown() override {
BrowserWithTestWindowTest::TearDown();
ui::ShutdownInputMethodForTesting();
delegate_ = nullptr;
candidate_window_controller_ = nullptr;
keyboard_ = nullptr;
manager_.reset();
}
scoped_refptr<InputMethodManagerImpl::StateImpl> GetActiveIMEState() {
return scoped_refptr<InputMethodManagerImpl::StateImpl>(
manager_->state_.get());
}
protected:
// Helper function to initialize component extension stuff for testing.
void InitComponentExtension() {
mock_delegate_ = new MockComponentExtIMEManagerDelegate();
mock_delegate_->set_ime_list(ime_list_);
std::unique_ptr<ComponentExtensionIMEManagerDelegate> delegate(
mock_delegate_);
// CreateNewState(nullptr) returns state with non-empty
// current_input_method. So SetState() triggers ChangeInputMethod().
manager_->SetState(
manager_->CreateNewState(ProfileManager::GetActiveUserProfile()));
std::vector<std::string> layouts;
layouts.push_back("us");
std::vector<std::string> languages;
languages.push_back("en-US");
// Note, for production, these SetEngineHandler are called when
// IMEEngineHandlerInterface is initialized via
// InitializeComponentextension.
InputMethodDescriptors descriptors;
manager_->GetActiveIMEState()->AddInputMethodExtension(
ImeIdFromEngineId(kNaclMozcUsId),
descriptors,
mock_engine_handler_.get());
manager_->GetActiveIMEState()->AddInputMethodExtension(
ImeIdFromEngineId(kExt2Engine1Id),
descriptors,
mock_engine_handler_.get());
manager_->InitializeComponentExtensionForTesting(std::move(delegate));
}
void InitImeList() {
ime_list_.clear();
ComponentExtensionIME ext_xkb;
ext_xkb.id = extension_ime_util::kXkbExtensionId;
ext_xkb.description = "ext_xkb_description";
ext_xkb.path = base::FilePath("ext_xkb_file_path");
ComponentExtensionEngine ext_xkb_engine_us;
ext_xkb_engine_us.engine_id = "xkb:us::eng";
ext_xkb_engine_us.display_name = "xkb:us::eng";
ext_xkb_engine_us.language_codes.push_back("en-US");
ext_xkb_engine_us.layouts.push_back("us");
ext_xkb.engines.push_back(ext_xkb_engine_us);
ComponentExtensionEngine ext_xkb_engine_intl;
ext_xkb_engine_intl.engine_id = "xkb:us:intl:eng";
ext_xkb_engine_intl.display_name = "xkb:us:intl:eng";
ext_xkb_engine_intl.language_codes.push_back("en-US");
ext_xkb_engine_intl.layouts.push_back("us(intl)");
ext_xkb.engines.push_back(ext_xkb_engine_intl);
ComponentExtensionEngine ext_xkb_engine_altgr_intl;
ext_xkb_engine_altgr_intl.engine_id = "xkb:us:altgr-intl:eng";
ext_xkb_engine_altgr_intl.display_name = "xkb:us:altgr-intl:eng";
ext_xkb_engine_altgr_intl.language_codes.push_back("en-US");
ext_xkb_engine_altgr_intl.layouts.push_back("us(altgr-intl)");
ext_xkb.engines.push_back(ext_xkb_engine_altgr_intl);
ComponentExtensionEngine ext_xkb_engine_dvorak;
ext_xkb_engine_dvorak.engine_id = "xkb:us:dvorak:eng";
ext_xkb_engine_dvorak.display_name = "xkb:us:dvorak:eng";
ext_xkb_engine_dvorak.language_codes.push_back("en-US");
ext_xkb_engine_dvorak.layouts.push_back("us(dvorak)");
ext_xkb.engines.push_back(ext_xkb_engine_dvorak);
ComponentExtensionEngine ext_xkb_engine_dvp;
ext_xkb_engine_dvp.engine_id = "xkb:us:dvp:eng";
ext_xkb_engine_dvp.display_name = "xkb:us:dvp:eng";
ext_xkb_engine_dvp.language_codes.push_back("en-US");
ext_xkb_engine_dvp.layouts.push_back("us(dvp)");
ext_xkb.engines.push_back(ext_xkb_engine_dvp);
ComponentExtensionEngine ext_xkb_engine_colemak;
ext_xkb_engine_colemak.engine_id = "xkb:us:colemak:eng";
ext_xkb_engine_colemak.display_name = "xkb:us:colemak:eng";
ext_xkb_engine_colemak.language_codes.push_back("en-US");
ext_xkb_engine_colemak.layouts.push_back("us(colemak)");
ext_xkb.engines.push_back(ext_xkb_engine_colemak);
ComponentExtensionEngine ext_xkb_engine_workman;
ext_xkb_engine_workman.engine_id = "xkb:us:workman:eng";
ext_xkb_engine_workman.display_name = "xkb:us:workman:eng";
ext_xkb_engine_workman.language_codes.push_back("en-US");
ext_xkb_engine_workman.layouts.push_back("us(workman)");
ext_xkb.engines.push_back(ext_xkb_engine_workman);
ComponentExtensionEngine ext_xkb_engine_workman_intl;
ext_xkb_engine_workman_intl.engine_id = "xkb:us:workman-intl:eng";
ext_xkb_engine_workman_intl.display_name = "xkb:us:workman-intl:eng";
ext_xkb_engine_workman_intl.language_codes.push_back("en-US");
ext_xkb_engine_workman_intl.layouts.push_back("us(workman-intl)");
ext_xkb.engines.push_back(ext_xkb_engine_workman_intl);
ComponentExtensionEngine ext_xkb_engine_fr;
ext_xkb_engine_fr.engine_id = "xkb:fr::fra";
ext_xkb_engine_fr.display_name = "xkb:fr::fra";
ext_xkb_engine_fr.language_codes.push_back("fr");
ext_xkb_engine_fr.layouts.push_back("fr");
ext_xkb.engines.push_back(ext_xkb_engine_fr);
ComponentExtensionEngine ext_xkb_engine_se;
ext_xkb_engine_se.engine_id = "xkb:se::swe";
ext_xkb_engine_se.display_name = "xkb:se::swe";
ext_xkb_engine_se.language_codes.push_back("sv");
ext_xkb_engine_se.layouts.push_back("se");
ext_xkb.engines.push_back(ext_xkb_engine_se);
ComponentExtensionEngine ext_xkb_engine_jp;
ext_xkb_engine_jp.engine_id = "xkb:jp::jpn";
ext_xkb_engine_jp.display_name = "xkb:jp::jpn";
ext_xkb_engine_jp.language_codes.push_back("ja");
ext_xkb_engine_jp.layouts.push_back("jp");
ext_xkb.engines.push_back(ext_xkb_engine_jp);
ComponentExtensionEngine ext_xkb_engine_ru;
ext_xkb_engine_ru.engine_id = "xkb:ru::rus";
ext_xkb_engine_ru.display_name = "xkb:ru::rus";
ext_xkb_engine_ru.language_codes.push_back("ru");
ext_xkb_engine_ru.layouts.push_back("ru");
ext_xkb.engines.push_back(ext_xkb_engine_ru);
ComponentExtensionEngine ext_xkb_engine_hu;
ext_xkb_engine_hu.engine_id = "xkb:hu::hun";
ext_xkb_engine_hu.display_name = "xkb:hu::hun";
ext_xkb_engine_hu.language_codes.push_back("hu");
ext_xkb_engine_hu.layouts.push_back("hu");
ext_xkb.engines.push_back(ext_xkb_engine_hu);
ime_list_.push_back(ext_xkb);
ComponentExtensionIME ext1;
ext1.id = extension_ime_util::kMozcExtensionId;
ext1.description = "ext1_description";
ext1.path = base::FilePath("ext1_file_path");
ComponentExtensionEngine ext1_engine1;
ext1_engine1.engine_id = "nacl_mozc_us";
ext1_engine1.display_name = "ext1_engine_1_display_name";
ext1_engine1.language_codes.push_back("ja");
ext1_engine1.layouts.push_back("us");
ext1.engines.push_back(ext1_engine1);
ComponentExtensionEngine ext1_engine2;
ext1_engine2.engine_id = "nacl_mozc_jp";
ext1_engine2.display_name = "ext1_engine_1_display_name";
ext1_engine2.language_codes.push_back("ja");
ext1_engine2.layouts.push_back("jp");
ext1.engines.push_back(ext1_engine2);
ime_list_.push_back(ext1);
ComponentExtensionIME ext2;
ext2.id = extension_ime_util::kT13nExtensionId;
ext2.description = "ext2_description";
ext2.path = base::FilePath("ext2_file_path");
ComponentExtensionEngine ext2_engine1;
ext2_engine1.engine_id = kExt2Engine1Id;
ext2_engine1.display_name = "ext2_engine_1_display_name";
ext2_engine1.language_codes.push_back("en");
ext2_engine1.layouts.push_back("us");
ext2.engines.push_back(ext2_engine1);
ComponentExtensionEngine ext2_engine2;
ext2_engine2.engine_id = kExt2Engine2Id;
ext2_engine2.display_name = "ext2_engine_2_display_name";
ext2_engine2.language_codes.push_back("en");
ext2_engine2.layouts.push_back("us(dvorak)");
ext2.engines.push_back(ext2_engine2);
ime_list_.push_back(ext2);
}
content::TestServiceManagerContext service_manager_context_;
std::unique_ptr<ChromeKeyboardControllerClientTestHelper>
chrome_keyboard_controller_client_test_helper_;
std::unique_ptr<InputMethodManagerImpl> manager_;
FakeInputMethodDelegate* delegate_;
MockCandidateWindowController* candidate_window_controller_;
std::unique_ptr<MockInputMethodEngine> mock_engine_handler_;
FakeImeKeyboard* keyboard_;
MockComponentExtIMEManagerDelegate* mock_delegate_;
std::vector<ComponentExtensionIME> ime_list_;
ui::ime::InputMethodMenuManager* menu_manager_;
private:
DISALLOW_COPY_AND_ASSIGN(InputMethodManagerImplTest);
};
TEST_F(InputMethodManagerImplTest, TestGetImeKeyboard) {
EXPECT_TRUE(manager_->GetImeKeyboard());
EXPECT_EQ(keyboard_, manager_->GetImeKeyboard());
}
TEST_F(InputMethodManagerImplTest, TestCandidateWindowObserver) {
TestCandidateWindowObserver observer;
candidate_window_controller_->NotifyCandidateWindowOpened(); // nop
candidate_window_controller_->NotifyCandidateWindowClosed(); // nop
manager_->AddCandidateWindowObserver(&observer);
candidate_window_controller_->NotifyCandidateWindowOpened();
EXPECT_EQ(1, observer.candidate_window_opened_count_);
candidate_window_controller_->NotifyCandidateWindowClosed();
EXPECT_EQ(1, observer.candidate_window_closed_count_);
candidate_window_controller_->NotifyCandidateWindowOpened();
EXPECT_EQ(2, observer.candidate_window_opened_count_);
candidate_window_controller_->NotifyCandidateWindowClosed();
EXPECT_EQ(2, observer.candidate_window_closed_count_);
manager_->RemoveCandidateWindowObserver(&observer);
}
TEST_F(InputMethodManagerImplTest, TestObserver) {
// For http://crbug.com/19655#c11 - (3). browser_state_monitor_unittest.cc is
// also for the scenario.
std::vector<std::string> keyboard_layouts;
keyboard_layouts.push_back("xkb:us::eng");
TestObserver observer;
InitComponentExtension();
manager_->AddObserver(&observer);
menu_manager_->AddObserver(&observer);
EXPECT_EQ(0, observer.input_method_changed_count_);
EXPECT_EQ(0, observer.input_method_extension_added_count_);
EXPECT_EQ(0, observer.input_method_extension_removed_count_);
manager_->GetActiveIMEState()->EnableLoginLayouts("en-US", keyboard_layouts);
EXPECT_EQ(8U, manager_->GetActiveIMEState()->GetActiveInputMethods()->size());
EXPECT_EQ(1, observer.input_method_changed_count_);
// Menu change is triggered only if current input method was actually changed.
EXPECT_EQ(0, observer.input_method_menu_item_changed_count_);
manager_->GetActiveIMEState()->ChangeInputMethod(
ImeIdFromEngineId("xkb:us:dvorak:eng"), false /* show_message */);
EXPECT_FALSE(observer.last_show_message_);
EXPECT_EQ(2, observer.input_method_changed_count_);
EXPECT_EQ(1, observer.input_method_menu_item_changed_count_);
manager_->GetActiveIMEState()->ChangeInputMethod(
ImeIdFromEngineId("xkb:us:dvorak:eng"), false /* show_message */);
EXPECT_FALSE(observer.last_show_message_);
// The observer is always notified even when the same input method ID is
// passed to ChangeInputMethod() more than twice.
// TODO(komatsu): Revisit if this is neccessary.
EXPECT_EQ(3, observer.input_method_changed_count_);
// If the same input method ID is passed, PropertyChanged() is not
// notified.
EXPECT_EQ(1, observer.input_method_menu_item_changed_count_);
// Add an ARC IME, remove it, then check the observer counts.
MockInputMethodEngine engine;
const std::string ime_id =
extension_ime_util::GetArcInputMethodID(kExtensionId1, "engine_id");
InputMethodDescriptor descriptor(ime_id, "arc ime", "AI", {"us"}, {"en-US"},
false /* is_login_keyboard */, GURL(),
GURL());
manager_->GetActiveIMEState()->AddInputMethodExtension(kExtensionId1,
{descriptor}, &engine);
EXPECT_EQ(1, observer.input_method_extension_added_count_);
EXPECT_EQ(0, observer.input_method_extension_removed_count_);
manager_->GetActiveIMEState()->RemoveInputMethodExtension(kExtensionId1);
EXPECT_EQ(1, observer.input_method_extension_added_count_);
EXPECT_EQ(1, observer.input_method_extension_removed_count_);
manager_->RemoveObserver(&observer);
menu_manager_->RemoveObserver(&observer);
}
TEST_F(InputMethodManagerImplTest, TestGetSupportedInputMethods) {
InitComponentExtension();
InputMethodDescriptors methods;
methods = manager_->GetComponentExtensionIMEManager()
->GetXkbIMEAsInputMethodDescriptor();
// Try to find random 4-5 layuts and IMEs to make sure the returned list is
// correct.
const InputMethodDescriptor* id_to_find =
manager_->GetInputMethodUtil()->GetInputMethodDescriptorFromId(
ImeIdFromEngineId(kNaclMozcUsId));
id_to_find = manager_->GetInputMethodUtil()->GetInputMethodDescriptorFromId(
ImeIdFromEngineId("xkb:us::eng"));
EXPECT_TRUE(Contain(methods, *id_to_find));
id_to_find = manager_->GetInputMethodUtil()->GetInputMethodDescriptorFromId(
ImeIdFromEngineId("xkb:us:dvorak:eng"));
EXPECT_TRUE(Contain(methods, *id_to_find));
id_to_find = manager_->GetInputMethodUtil()->GetInputMethodDescriptorFromId(
ImeIdFromEngineId("xkb:fr::fra"));
EXPECT_TRUE(Contain(methods, *id_to_find));
}
TEST_F(InputMethodManagerImplTest, TestEnableLayouts) {
// Currently 8 keyboard layouts are supported for en-US, and 1 for ja. See
// ibus_input_method.txt.
std::vector<std::string> keyboard_layouts;
InitComponentExtension();
manager_->GetActiveIMEState()->EnableLoginLayouts("en-US", keyboard_layouts);
EXPECT_EQ(8U, manager_->GetActiveIMEState()->GetNumActiveInputMethods());
// For http://crbug.com/19655#c11 - (5)
// The hardware keyboard layout "xkb:us::eng" is always active, hence 2U.
manager_->GetActiveIMEState()->EnableLoginLayouts(
"ja", keyboard_layouts); // Japanese
EXPECT_EQ(2U, manager_->GetActiveIMEState()->GetNumActiveInputMethods());
}
TEST_F(InputMethodManagerImplTest, TestEnableLayoutsAndCurrentInputMethod) {
// For http://crbug.com/329061
std::vector<std::string> keyboard_layouts;
keyboard_layouts.push_back(ImeIdFromEngineId("xkb:se::swe"));
InitComponentExtension();
manager_->GetActiveIMEState()->EnableLoginLayouts("en-US", keyboard_layouts);
const std::string im_id =
manager_->GetActiveIMEState()->GetCurrentInputMethod().id();
EXPECT_EQ(ImeIdFromEngineId("xkb:se::swe"), im_id);
}
TEST_F(InputMethodManagerImplTest, TestEnableLayoutsNonUsHardwareKeyboard) {
InitComponentExtension();
// The physical layout is French.
manager_->GetInputMethodUtil()->SetHardwareKeyboardLayoutForTesting(
"xkb:fr::fra");
manager_->GetActiveIMEState()->EnableLoginLayouts(
"en-US",
manager_->GetInputMethodUtil()->GetHardwareLoginInputMethodIds());
EXPECT_EQ(
9U,
manager_->GetActiveIMEState()->GetNumActiveInputMethods()); // 8 + French
// The physical layout is Japanese.
manager_->GetInputMethodUtil()->SetHardwareKeyboardLayoutForTesting(
"xkb:jp::jpn");
manager_->GetActiveIMEState()->EnableLoginLayouts(
"ja", manager_->GetInputMethodUtil()->GetHardwareLoginInputMethodIds());
// "xkb:us::eng" is not needed, hence 1.
EXPECT_EQ(1U, manager_->GetActiveIMEState()->GetNumActiveInputMethods());
// The physical layout is Russian.
manager_->GetInputMethodUtil()->SetHardwareKeyboardLayoutForTesting(
"xkb:ru::rus");
manager_->GetActiveIMEState()->EnableLoginLayouts(
"ru", manager_->GetInputMethodUtil()->GetHardwareLoginInputMethodIds());
// "xkb:us::eng" only.
EXPECT_EQ(1U, manager_->GetActiveIMEState()->GetNumActiveInputMethods());
EXPECT_EQ(ImeIdFromEngineId("xkb:us::eng"),
manager_->GetActiveIMEState()->GetActiveInputMethodIds().front());
}
TEST_F(InputMethodManagerImplTest, TestEnableMultipleHardwareKeyboardLayout) {
InitComponentExtension();
// The physical layouts are French and Hungarian.
manager_->GetInputMethodUtil()->SetHardwareKeyboardLayoutForTesting(
"xkb:fr::fra,xkb:hu::hun");
manager_->GetActiveIMEState()->EnableLoginLayouts(
"en-US",
manager_->GetInputMethodUtil()->GetHardwareLoginInputMethodIds());
// 8 + French + Hungarian
EXPECT_EQ(10U, manager_->GetActiveIMEState()->GetNumActiveInputMethods());
}
TEST_F(InputMethodManagerImplTest,
TestEnableMultipleHardwareKeyboardLayout_NoLoginKeyboard) {
InitComponentExtension();
// The physical layouts are English (US) and Russian.
manager_->GetInputMethodUtil()->SetHardwareKeyboardLayoutForTesting(
"xkb:us::eng,xkb:ru::rus");
manager_->GetActiveIMEState()->EnableLoginLayouts(
"ru", manager_->GetInputMethodUtil()->GetHardwareLoginInputMethodIds());
// xkb:us:eng
EXPECT_EQ(1U, manager_->GetActiveIMEState()->GetNumActiveInputMethods());
}
TEST_F(InputMethodManagerImplTest, TestActiveInputMethods) {
InitComponentExtension();
std::vector<std::string> keyboard_layouts;
manager_->GetActiveIMEState()->EnableLoginLayouts(
"ja", keyboard_layouts); // Japanese
EXPECT_EQ(2U, manager_->GetActiveIMEState()->GetNumActiveInputMethods());
std::unique_ptr<InputMethodDescriptors> methods(
manager_->GetActiveIMEState()->GetActiveInputMethods());
ASSERT_TRUE(methods.get());
EXPECT_EQ(2U, methods->size());
const InputMethodDescriptor* id_to_find =
manager_->GetInputMethodUtil()->GetInputMethodDescriptorFromId(
ImeIdFromEngineId("xkb:us::eng"));
EXPECT_TRUE(id_to_find && Contain(*methods.get(), *id_to_find));
id_to_find = manager_->GetInputMethodUtil()->GetInputMethodDescriptorFromId(
ImeIdFromEngineId("xkb:jp::jpn"));
EXPECT_TRUE(id_to_find && Contain(*methods.get(), *id_to_find));
}
TEST_F(InputMethodManagerImplTest, TestEnableTwoLayouts) {
// For http://crbug.com/19655#c11 - (8), step 6.
TestObserver observer;
InitComponentExtension();
manager_->AddObserver(&observer);
manager_->SetUISessionState(InputMethodManager::STATE_BROWSER_SCREEN);
std::vector<std::string> ids;
ids.push_back(ImeIdFromEngineId("xkb:us:dvorak:eng"));
ids.push_back(ImeIdFromEngineId("xkb:us:colemak:eng"));
EXPECT_TRUE(manager_->GetActiveIMEState()->ReplaceEnabledInputMethods(ids));
EXPECT_EQ(2U, manager_->GetActiveIMEState()->GetNumActiveInputMethods());
// Since all the IDs added avobe are keyboard layouts, Start() should not be
// called.
EXPECT_EQ(1, observer.input_method_changed_count_);
EXPECT_EQ(ImeIdFromEngineId(ids[0]),
manager_->GetActiveIMEState()->GetCurrentInputMethod().id());
EXPECT_EQ("us(dvorak)", keyboard_->last_layout_);
// Disable Dvorak.
ids.erase(ids.begin());
EXPECT_TRUE(manager_->GetActiveIMEState()->ReplaceEnabledInputMethods(ids));
EXPECT_EQ(1U, manager_->GetActiveIMEState()->GetNumActiveInputMethods());
EXPECT_EQ(2, observer.input_method_changed_count_);
EXPECT_EQ(ImeIdFromEngineId(ids[0]), // colemak
manager_->GetActiveIMEState()->GetCurrentInputMethod().id());
EXPECT_EQ("us(colemak)", keyboard_->last_layout_);
manager_->RemoveObserver(&observer);
}
TEST_F(InputMethodManagerImplTest, TestEnableThreeLayouts) {
// For http://crbug.com/19655#c11 - (9).
TestObserver observer;
InitComponentExtension();
manager_->AddObserver(&observer);
manager_->SetUISessionState(InputMethodManager::STATE_BROWSER_SCREEN);
std::vector<std::string> ids;
ids.push_back(ImeIdFromEngineId("xkb:us::eng"));
ids.push_back(ImeIdFromEngineId("xkb:us:dvorak:eng"));
ids.push_back(ImeIdFromEngineId("xkb:us:colemak:eng"));
EXPECT_TRUE(manager_->GetActiveIMEState()->ReplaceEnabledInputMethods(ids));
EXPECT_EQ(3U, manager_->GetActiveIMEState()->GetNumActiveInputMethods());
EXPECT_EQ(1, observer.input_method_changed_count_);
EXPECT_EQ(ImeIdFromEngineId(ids[0]),
manager_->GetActiveIMEState()->GetCurrentInputMethod().id());
EXPECT_EQ("us", keyboard_->last_layout_);
// Switch to Dvorak.
manager_->GetActiveIMEState()->SwitchToNextInputMethod();
EXPECT_EQ(2, observer.input_method_changed_count_);
EXPECT_EQ(ImeIdFromEngineId(ids[1]),
manager_->GetActiveIMEState()->GetCurrentInputMethod().id());
EXPECT_EQ("us(dvorak)", keyboard_->last_layout_);
// Disable Dvorak.
ids.erase(ids.begin() + 1);
EXPECT_TRUE(manager_->GetActiveIMEState()->ReplaceEnabledInputMethods(ids));
EXPECT_EQ(2U, manager_->GetActiveIMEState()->GetNumActiveInputMethods());
EXPECT_EQ(3, observer.input_method_changed_count_);
EXPECT_EQ(ImeIdFromEngineId(ids[0]), // US Qwerty
manager_->GetActiveIMEState()->GetCurrentInputMethod().id());
EXPECT_EQ("us", keyboard_->last_layout_);
manager_->RemoveObserver(&observer);
}
TEST_F(InputMethodManagerImplTest, TestEnableLayoutAndIme) {
// For http://crbug.com/19655#c11 - (10).
TestObserver observer;
InitComponentExtension();
manager_->AddObserver(&observer);
manager_->SetUISessionState(InputMethodManager::STATE_BROWSER_SCREEN);
std::vector<std::string> ids;
ids.push_back(ImeIdFromEngineId("xkb:us:dvorak:eng"));
ids.push_back(ImeIdFromEngineId(kNaclMozcUsId));
EXPECT_TRUE(manager_->GetActiveIMEState()->ReplaceEnabledInputMethods(ids));
EXPECT_EQ(1, observer.input_method_changed_count_);
EXPECT_EQ(ImeIdFromEngineId(ids[0]),
manager_->GetActiveIMEState()->GetCurrentInputMethod().id());
EXPECT_EQ("us(dvorak)", keyboard_->last_layout_);
// Switch to Mozc
manager_->GetActiveIMEState()->SwitchToNextInputMethod();
EXPECT_EQ(2, observer.input_method_changed_count_);
EXPECT_EQ(ImeIdFromEngineId(ids[1]),
manager_->GetActiveIMEState()->GetCurrentInputMethod().id());
EXPECT_EQ("us", keyboard_->last_layout_);
// Disable Mozc.
ids.erase(ids.begin() + 1);
EXPECT_TRUE(manager_->GetActiveIMEState()->ReplaceEnabledInputMethods(ids));
EXPECT_EQ(1U, manager_->GetActiveIMEState()->GetNumActiveInputMethods());
EXPECT_EQ(ImeIdFromEngineId(ids[0]),
manager_->GetActiveIMEState()->GetCurrentInputMethod().id());
EXPECT_EQ("us(dvorak)", keyboard_->last_layout_);
}
TEST_F(InputMethodManagerImplTest, TestEnableLayoutAndIme2) {
// For http://crbug.com/19655#c11 - (11).
TestObserver observer;
InitComponentExtension();
manager_->AddObserver(&observer);
manager_->SetUISessionState(InputMethodManager::STATE_BROWSER_SCREEN);
std::vector<std::string> ids;
ids.push_back(ImeIdFromEngineId("xkb:us:dvorak:eng"));
ids.push_back(ImeIdFromEngineId(kNaclMozcUsId));
EXPECT_TRUE(manager_->GetActiveIMEState()->ReplaceEnabledInputMethods(ids));
EXPECT_EQ(1, observer.input_method_changed_count_);
EXPECT_EQ(ImeIdFromEngineId(ids[0]),
manager_->GetActiveIMEState()->GetCurrentInputMethod().id());
EXPECT_EQ("us(dvorak)", keyboard_->last_layout_);
// Disable Dvorak.
ids.erase(ids.begin());
EXPECT_TRUE(manager_->GetActiveIMEState()->ReplaceEnabledInputMethods(ids));
EXPECT_EQ(1U, manager_->GetActiveIMEState()->GetNumActiveInputMethods());
EXPECT_EQ(ImeIdFromEngineId(ids[0]), // Mozc
manager_->GetActiveIMEState()->GetCurrentInputMethod().id());
EXPECT_EQ("us", keyboard_->last_layout_);
manager_->RemoveObserver(&observer);
}
TEST_F(InputMethodManagerImplTest, TestEnableImes) {
TestObserver observer;
InitComponentExtension();
manager_->AddObserver(&observer);
manager_->SetUISessionState(InputMethodManager::STATE_BROWSER_SCREEN);
std::vector<std::string> ids;
ids.push_back(ImeIdFromEngineId(kExt2Engine1Id));
ids.push_back("mozc-dv");
EXPECT_TRUE(manager_->GetActiveIMEState()->ReplaceEnabledInputMethods(ids));
EXPECT_EQ(1, observer.input_method_changed_count_);
EXPECT_EQ(ImeIdFromEngineId(ids[0]),
manager_->GetActiveIMEState()->GetCurrentInputMethod().id());
EXPECT_EQ("us", keyboard_->last_layout_);
manager_->RemoveObserver(&observer);
}
TEST_F(InputMethodManagerImplTest, TestEnableUnknownIds) {
TestObserver observer;
InitComponentExtension();
manager_->AddObserver(&observer);
manager_->SetUISessionState(InputMethodManager::STATE_BROWSER_SCREEN);
std::vector<std::string> ids;
ids.push_back("xkb:tl::tlh"); // Klingon, which is not supported.
ids.push_back("unknown-super-cool-ime");
EXPECT_FALSE(manager_->GetActiveIMEState()->ReplaceEnabledInputMethods(ids));
// TODO(yusukes): Should we fall back to the hardware keyboard layout in this
// case?
EXPECT_EQ(0, observer.input_method_changed_count_);
manager_->RemoveObserver(&observer);
}
TEST_F(InputMethodManagerImplTest, TestEnableLayoutsThenLock) {
// For http://crbug.com/19655#c11 - (14).
TestObserver observer;
InitComponentExtension();
manager_->AddObserver(&observer);
manager_->SetUISessionState(InputMethodManager::STATE_BROWSER_SCREEN);
std::vector<std::string> ids;
ids.push_back(ImeIdFromEngineId("xkb:us::eng"));
ids.push_back(ImeIdFromEngineId("xkb:us:dvorak:eng"));
EXPECT_TRUE(manager_->GetActiveIMEState()->ReplaceEnabledInputMethods(ids));
EXPECT_EQ(2U, manager_->GetActiveIMEState()->GetNumActiveInputMethods());
EXPECT_EQ(1, observer.input_method_changed_count_);
EXPECT_EQ(ImeIdFromEngineId(ids[0]),
manager_->GetActiveIMEState()->GetCurrentInputMethod().id());
EXPECT_EQ("us", keyboard_->last_layout_);
// Switch to Dvorak.
manager_->GetActiveIMEState()->SwitchToNextInputMethod();
EXPECT_EQ(2, observer.input_method_changed_count_);
EXPECT_EQ(ImeIdFromEngineId(ids[1]),
manager_->GetActiveIMEState()->GetCurrentInputMethod().id());
EXPECT_EQ("us(dvorak)", keyboard_->last_layout_);
// Lock screen
scoped_refptr<input_method::InputMethodManager::State> saved_ime_state =
manager_->GetActiveIMEState();
manager_->SetState(saved_ime_state->Clone());
manager_->GetActiveIMEState()->EnableLockScreenLayouts();
manager_->SetUISessionState(InputMethodManager::STATE_LOCK_SCREEN);
EXPECT_EQ(2U, manager_->GetActiveIMEState()->GetNumActiveInputMethods());
EXPECT_EQ(ImeIdFromEngineId(ids[1]), // still Dvorak
manager_->GetActiveIMEState()->GetCurrentInputMethod().id());
EXPECT_EQ("us(dvorak)", keyboard_->last_layout_);
// Switch back to Qwerty.
manager_->GetActiveIMEState()->SwitchToNextInputMethod();
EXPECT_EQ(ImeIdFromEngineId(ids[0]),
manager_->GetActiveIMEState()->GetCurrentInputMethod().id());
EXPECT_EQ("us", keyboard_->last_layout_);
// Unlock screen. The original state, Dvorak, is restored.
manager_->SetState(saved_ime_state);
manager_->SetUISessionState(InputMethodManager::STATE_BROWSER_SCREEN);
EXPECT_EQ(2U, manager_->GetActiveIMEState()->GetNumActiveInputMethods());
EXPECT_EQ(ImeIdFromEngineId(ids[1]),
manager_->GetActiveIMEState()->GetCurrentInputMethod().id());
EXPECT_EQ("us(dvorak)", keyboard_->last_layout_);
manager_->RemoveObserver(&observer);
}
TEST_F(InputMethodManagerImplTest, SwitchInputMethodTest) {
// For http://crbug.com/19655#c11 - (15).
TestObserver observer;
InitComponentExtension();
manager_->AddObserver(&observer);
manager_->SetUISessionState(InputMethodManager::STATE_BROWSER_SCREEN);
std::vector<std::string> ids;
ids.push_back(ImeIdFromEngineId("xkb:us:dvorak:eng"));
ids.push_back(ImeIdFromEngineId(kExt2Engine2Id));
ids.push_back(ImeIdFromEngineId(kExt2Engine1Id));
EXPECT_TRUE(manager_->GetActiveIMEState()->ReplaceEnabledInputMethods(ids));
EXPECT_EQ(3U, manager_->GetActiveIMEState()->GetNumActiveInputMethods());
EXPECT_EQ(1, observer.input_method_changed_count_);
EXPECT_EQ(ImeIdFromEngineId(ids[0]),
manager_->GetActiveIMEState()->GetCurrentInputMethod().id());
EXPECT_EQ("us(dvorak)", keyboard_->last_layout_);
// Switch to Mozc.
manager_->GetActiveIMEState()->SwitchToNextInputMethod();
EXPECT_EQ(2, observer.input_method_changed_count_);
EXPECT_EQ(ImeIdFromEngineId(ids[1]),
manager_->GetActiveIMEState()->GetCurrentInputMethod().id());
EXPECT_EQ("us(dvorak)", keyboard_->last_layout_);
// Lock screen
scoped_refptr<input_method::InputMethodManager::State> saved_ime_state =
manager_->GetActiveIMEState();
manager_->SetState(saved_ime_state->Clone());
manager_->GetActiveIMEState()->EnableLockScreenLayouts();
manager_->SetUISessionState(InputMethodManager::STATE_LOCK_SCREEN);
EXPECT_EQ(2U,
manager_->GetActiveIMEState()
->GetNumActiveInputMethods()); // Qwerty+Dvorak.
EXPECT_EQ(ImeIdFromEngineId("xkb:us:dvorak:eng"),
manager_->GetActiveIMEState()->GetCurrentInputMethod().id());
EXPECT_EQ("us(dvorak)", keyboard_->last_layout_);
manager_->GetActiveIMEState()->SwitchToNextInputMethod();
EXPECT_EQ(ImeIdFromEngineId("xkb:us::eng"), // The hardware keyboard layout.
manager_->GetActiveIMEState()->GetCurrentInputMethod().id());
EXPECT_EQ("us", keyboard_->last_layout_);
// Unlock screen. The original state, pinyin-dv, is restored.
manager_->SetState(saved_ime_state);
manager_->SetUISessionState(InputMethodManager::STATE_BROWSER_SCREEN);
EXPECT_EQ(3U,
manager_->GetActiveIMEState()
->GetNumActiveInputMethods()); // Dvorak and 2 IMEs.
EXPECT_EQ(ImeIdFromEngineId(ids[1]),
manager_->GetActiveIMEState()->GetCurrentInputMethod().id());
EXPECT_EQ("us(dvorak)", keyboard_->last_layout_);
manager_->RemoveObserver(&observer);
}
TEST_F(InputMethodManagerImplTest, TestXkbSetting) {
EXPECT_EQ(0, keyboard_->set_current_keyboard_layout_by_name_count_);
// For http://crbug.com/19655#c11 - (8), step 7-11.
InitComponentExtension();
EXPECT_EQ(1, keyboard_->set_current_keyboard_layout_by_name_count_);
manager_->SetUISessionState(InputMethodManager::STATE_BROWSER_SCREEN);
std::vector<std::string> ids;
ids.push_back(ImeIdFromEngineId("xkb:us:dvorak:eng"));
ids.push_back(ImeIdFromEngineId("xkb:us:colemak:eng"));
ids.push_back(ImeIdFromEngineId(kNaclMozcJpId));
ids.push_back(ImeIdFromEngineId(kNaclMozcUsId));
EXPECT_TRUE(manager_->GetActiveIMEState()->ReplaceEnabledInputMethods(ids));
EXPECT_EQ(4U, manager_->GetActiveIMEState()->GetNumActiveInputMethods());
EXPECT_EQ(2, keyboard_->set_current_keyboard_layout_by_name_count_);
// See input_methods.txt for an expected XKB layout name.
EXPECT_EQ("us(dvorak)", keyboard_->last_layout_);
manager_->GetActiveIMEState()->SwitchToNextInputMethod();
EXPECT_EQ(3, keyboard_->set_current_keyboard_layout_by_name_count_);
EXPECT_EQ("us(colemak)", keyboard_->last_layout_);
manager_->GetActiveIMEState()->SwitchToNextInputMethod();
EXPECT_EQ(4, keyboard_->set_current_keyboard_layout_by_name_count_);
EXPECT_EQ("jp", keyboard_->last_layout_);
manager_->GetActiveIMEState()->SwitchToNextInputMethod();
EXPECT_EQ(5, keyboard_->set_current_keyboard_layout_by_name_count_);
EXPECT_EQ("us", keyboard_->last_layout_);
manager_->GetActiveIMEState()->SwitchToNextInputMethod();
EXPECT_EQ(6, keyboard_->set_current_keyboard_layout_by_name_count_);
EXPECT_EQ("us(dvorak)", keyboard_->last_layout_);
// Disable Dvorak.
ids.erase(ids.begin());
EXPECT_TRUE(manager_->GetActiveIMEState()->ReplaceEnabledInputMethods(ids));
EXPECT_EQ(3U, manager_->GetActiveIMEState()->GetNumActiveInputMethods());
EXPECT_EQ(7, keyboard_->set_current_keyboard_layout_by_name_count_);
EXPECT_EQ("us(colemak)", keyboard_->last_layout_);
}
TEST_F(InputMethodManagerImplTest, TestActivateInputMethodMenuItem) {
const std::string kKey = "key";
ui::ime::InputMethodMenuItemList menu_list;
menu_list.push_back(ui::ime::InputMethodMenuItem(
kKey, "label", false, false));
menu_manager_->SetCurrentInputMethodMenuItemList(menu_list);
manager_->ActivateInputMethodMenuItem(kKey);
EXPECT_EQ(kKey, mock_engine_handler_->last_activated_property());
// Key2 is not registered, so activated property should not be changed.
manager_->ActivateInputMethodMenuItem("key2");
EXPECT_EQ(kKey, mock_engine_handler_->last_activated_property());
}
TEST_F(InputMethodManagerImplTest, TestGetCurrentInputMethodProperties) {
InitComponentExtension();
EXPECT_TRUE(menu_manager_->GetCurrentInputMethodMenuItemList().empty());
manager_->SetUISessionState(InputMethodManager::STATE_BROWSER_SCREEN);
std::vector<std::string> ids;
ids.push_back(ImeIdFromEngineId("xkb:us::eng"));
ids.push_back(ImeIdFromEngineId(kNaclMozcUsId));
EXPECT_TRUE(manager_->GetActiveIMEState()->ReplaceEnabledInputMethods(ids));
EXPECT_EQ(2U, manager_->GetActiveIMEState()->GetNumActiveInputMethods());
EXPECT_TRUE(menu_manager_->GetCurrentInputMethodMenuItemList().empty());
manager_->GetActiveIMEState()->ChangeInputMethod(
ImeIdFromEngineId(kNaclMozcUsId), false /* show_message */);
ui::ime::InputMethodMenuItemList current_property_list;
current_property_list.push_back(ui::ime::InputMethodMenuItem(
"key", "label", false, false));
menu_manager_->SetCurrentInputMethodMenuItemList(current_property_list);
ASSERT_EQ(1U, menu_manager_->GetCurrentInputMethodMenuItemList().size());
EXPECT_EQ("key",
menu_manager_->GetCurrentInputMethodMenuItemList().at(0).key);
manager_->GetActiveIMEState()->ChangeInputMethod("xkb:us::eng",
false /* show_message */);
EXPECT_TRUE(menu_manager_->GetCurrentInputMethodMenuItemList().empty());
}
TEST_F(InputMethodManagerImplTest, TestGetCurrentInputMethodPropertiesTwoImes) {
InitComponentExtension();
EXPECT_TRUE(menu_manager_->GetCurrentInputMethodMenuItemList().empty());
manager_->SetUISessionState(InputMethodManager::STATE_BROWSER_SCREEN);
std::vector<std::string> ids;
ids.push_back(ImeIdFromEngineId(kNaclMozcUsId)); // Japanese
ids.push_back(ImeIdFromEngineId(kExt2Engine1Id)); // T-Chinese
EXPECT_TRUE(manager_->GetActiveIMEState()->ReplaceEnabledInputMethods(ids));
EXPECT_EQ(2U, manager_->GetActiveIMEState()->GetNumActiveInputMethods());
EXPECT_TRUE(menu_manager_->GetCurrentInputMethodMenuItemList().empty());
ui::ime::InputMethodMenuItemList current_property_list;
current_property_list.push_back(ui::ime::InputMethodMenuItem("key-mozc",
"label",
false,
false));
menu_manager_->SetCurrentInputMethodMenuItemList(current_property_list);
ASSERT_EQ(1U, menu_manager_->GetCurrentInputMethodMenuItemList().size());
EXPECT_EQ("key-mozc",
menu_manager_->GetCurrentInputMethodMenuItemList().at(0).key);
manager_->GetActiveIMEState()->ChangeInputMethod(
ImeIdFromEngineId(kExt2Engine1Id), false /* show_message */);
// Since the IME is changed, the property for mozc Japanese should be hidden.
EXPECT_TRUE(menu_manager_->GetCurrentInputMethodMenuItemList().empty());
// Asynchronous property update signal from mozc-chewing.
current_property_list.clear();
current_property_list.push_back(ui::ime::InputMethodMenuItem(
"key-chewing", "label", false, false));
menu_manager_->SetCurrentInputMethodMenuItemList(current_property_list);
ASSERT_EQ(1U, menu_manager_->GetCurrentInputMethodMenuItemList().size());
EXPECT_EQ("key-chewing",
menu_manager_->GetCurrentInputMethodMenuItemList().at(0).key);
}
TEST_F(InputMethodManagerImplTest, TestNextInputMethod) {
TestObserver observer;
InitComponentExtension();
manager_->AddObserver(&observer);
std::vector<std::string> keyboard_layouts;
keyboard_layouts.push_back(ImeIdFromEngineId("xkb:us::eng"));
// For http://crbug.com/19655#c11 - (1)
manager_->GetActiveIMEState()->EnableLoginLayouts("en-US", keyboard_layouts);
EXPECT_EQ(8U, manager_->GetActiveIMEState()->GetNumActiveInputMethods());
EXPECT_EQ(ImeIdFromEngineId("xkb:us::eng"),
manager_->GetActiveIMEState()->GetCurrentInputMethod().id());
EXPECT_EQ("us", keyboard_->last_layout_);
manager_->GetActiveIMEState()->SwitchToNextInputMethod();
EXPECT_TRUE(observer.last_show_message_);
EXPECT_EQ(ImeIdFromEngineId("xkb:us:intl:eng"),
manager_->GetActiveIMEState()->GetCurrentInputMethod().id());
EXPECT_EQ("us(intl)", keyboard_->last_layout_);
manager_->GetActiveIMEState()->SwitchToNextInputMethod();
EXPECT_TRUE(observer.last_show_message_);
EXPECT_EQ(ImeIdFromEngineId("xkb:us:altgr-intl:eng"),
manager_->GetActiveIMEState()->GetCurrentInputMethod().id());
EXPECT_EQ("us(altgr-intl)", keyboard_->last_layout_);
manager_->GetActiveIMEState()->SwitchToNextInputMethod();
EXPECT_TRUE(observer.last_show_message_);
EXPECT_EQ(ImeIdFromEngineId("xkb:us:dvorak:eng"),
manager_->GetActiveIMEState()->GetCurrentInputMethod().id());
EXPECT_EQ("us(dvorak)", keyboard_->last_layout_);
manager_->GetActiveIMEState()->SwitchToNextInputMethod();
EXPECT_TRUE(observer.last_show_message_);
EXPECT_EQ(ImeIdFromEngineId("xkb:us:dvp:eng"),
manager_->GetActiveIMEState()->GetCurrentInputMethod().id());
EXPECT_EQ("us(dvp)", keyboard_->last_layout_);
manager_->GetActiveIMEState()->SwitchToNextInputMethod();
EXPECT_TRUE(observer.last_show_message_);
EXPECT_EQ(ImeIdFromEngineId("xkb:us:colemak:eng"),
manager_->GetActiveIMEState()->GetCurrentInputMethod().id());
EXPECT_EQ("us(colemak)", keyboard_->last_layout_);
manager_->GetActiveIMEState()->SwitchToNextInputMethod();
EXPECT_TRUE(observer.last_show_message_);
EXPECT_EQ(ImeIdFromEngineId("xkb:us:workman:eng"),
manager_->GetActiveIMEState()->GetCurrentInputMethod().id());
EXPECT_EQ("us(workman)", keyboard_->last_layout_);
manager_->GetActiveIMEState()->SwitchToNextInputMethod();
EXPECT_TRUE(observer.last_show_message_);
EXPECT_EQ(ImeIdFromEngineId("xkb:us:workman-intl:eng"),
manager_->GetActiveIMEState()->GetCurrentInputMethod().id());
EXPECT_EQ("us(workman-intl)", keyboard_->last_layout_);
manager_->GetActiveIMEState()->SwitchToNextInputMethod();
EXPECT_TRUE(observer.last_show_message_);
EXPECT_EQ(ImeIdFromEngineId("xkb:us::eng"),
manager_->GetActiveIMEState()->GetCurrentInputMethod().id());
EXPECT_EQ("us", keyboard_->last_layout_);
manager_->RemoveObserver(&observer);
}
TEST_F(InputMethodManagerImplTest, TestLastUsedInputMethod) {
TestObserver observer;
InitComponentExtension();
manager_->AddObserver(&observer);
std::vector<std::string> keyboard_layouts;
keyboard_layouts.push_back(ImeIdFromEngineId("xkb:us::eng"));
manager_->GetActiveIMEState()->EnableLoginLayouts("en-US", keyboard_layouts);
EXPECT_EQ(8U, manager_->GetActiveIMEState()->GetNumActiveInputMethods());
EXPECT_EQ(ImeIdFromEngineId("xkb:us::eng"),
manager_->GetActiveIMEState()->GetCurrentInputMethod().id());
EXPECT_EQ("us", keyboard_->last_layout_);
manager_->GetActiveIMEState()->SwitchToNextInputMethod();
EXPECT_TRUE(observer.last_show_message_);
EXPECT_EQ(ImeIdFromEngineId("xkb:us:intl:eng"),
manager_->GetActiveIMEState()->GetCurrentInputMethod().id());
EXPECT_EQ("us(intl)", keyboard_->last_layout_);
manager_->GetActiveIMEState()->SwitchToLastUsedInputMethod();
EXPECT_TRUE(observer.last_show_message_);
EXPECT_EQ(ImeIdFromEngineId("xkb:us::eng"),
manager_->GetActiveIMEState()->GetCurrentInputMethod().id());
EXPECT_EQ("us", keyboard_->last_layout_);
manager_->GetActiveIMEState()->SwitchToLastUsedInputMethod();
EXPECT_TRUE(observer.last_show_message_);
EXPECT_EQ(ImeIdFromEngineId("xkb:us:intl:eng"),
manager_->GetActiveIMEState()->GetCurrentInputMethod().id());
EXPECT_EQ("us(intl)", keyboard_->last_layout_);
manager_->GetActiveIMEState()->SwitchToLastUsedInputMethod();
EXPECT_TRUE(observer.last_show_message_);
EXPECT_EQ(ImeIdFromEngineId("xkb:us::eng"),
manager_->GetActiveIMEState()->GetCurrentInputMethod().id());
EXPECT_EQ("us", keyboard_->last_layout_);
manager_->GetActiveIMEState()->SwitchToNextInputMethod();
EXPECT_TRUE(observer.last_show_message_);
EXPECT_EQ(ImeIdFromEngineId("xkb:us:intl:eng"),
manager_->GetActiveIMEState()->GetCurrentInputMethod().id());
EXPECT_EQ("us(intl)", keyboard_->last_layout_);
manager_->GetActiveIMEState()->SwitchToNextInputMethod();
EXPECT_TRUE(observer.last_show_message_);
EXPECT_EQ(ImeIdFromEngineId("xkb:us:altgr-intl:eng"),
manager_->GetActiveIMEState()->GetCurrentInputMethod().id());
EXPECT_EQ("us(altgr-intl)", keyboard_->last_layout_);
manager_->GetActiveIMEState()->SwitchToLastUsedInputMethod();
EXPECT_TRUE(observer.last_show_message_);
EXPECT_EQ(ImeIdFromEngineId("xkb:us:intl:eng"),
manager_->GetActiveIMEState()->GetCurrentInputMethod().id());
EXPECT_EQ("us(intl)", keyboard_->last_layout_);
manager_->GetActiveIMEState()->SwitchToLastUsedInputMethod();
EXPECT_TRUE(observer.last_show_message_);
EXPECT_EQ(ImeIdFromEngineId("xkb:us:altgr-intl:eng"),
manager_->GetActiveIMEState()->GetCurrentInputMethod().id());
EXPECT_EQ("us(altgr-intl)", keyboard_->last_layout_);
manager_->RemoveObserver(&observer);
}
TEST_F(InputMethodManagerImplTest, CycleInputMethodForOneActiveInputMethod) {
InitComponentExtension();
// Simulate a single input method.
std::vector<std::string> ids;
ids.push_back(ImeIdFromEngineId("xkb:us::eng"));
EXPECT_TRUE(manager_->GetActiveIMEState()->ReplaceEnabledInputMethods(ids));
EXPECT_EQ(1U, manager_->GetActiveIMEState()->GetNumActiveInputMethods());
// Switching to next does nothing.
manager_->GetActiveIMEState()->SwitchToNextInputMethod();
EXPECT_EQ(ImeIdFromEngineId("xkb:us::eng"),
manager_->GetActiveIMEState()->GetCurrentInputMethod().id());
// Switching to last-used does nothing.
manager_->GetActiveIMEState()->SwitchToLastUsedInputMethod();
EXPECT_EQ(ImeIdFromEngineId("xkb:us::eng"),
manager_->GetActiveIMEState()->GetCurrentInputMethod().id());
}
TEST_F(InputMethodManagerImplTest, TestAddRemoveExtensionInputMethods) {
TestObserver observer;
InitComponentExtension();
manager_->AddObserver(&observer);
manager_->SetUISessionState(InputMethodManager::STATE_BROWSER_SCREEN);
std::vector<std::string> ids;
ids.push_back(ImeIdFromEngineId("xkb:us:dvorak:eng"));
EXPECT_TRUE(manager_->GetActiveIMEState()->ReplaceEnabledInputMethods(ids));
EXPECT_EQ(1U, manager_->GetActiveIMEState()->GetNumActiveInputMethods());
EXPECT_EQ(1, observer.input_method_changed_count_);
EXPECT_EQ(ImeIdFromEngineId(ids[0]),
manager_->GetActiveIMEState()->GetCurrentInputMethod().id());
EXPECT_EQ("us(dvorak)", keyboard_->last_layout_);
// Add two Extension IMEs.
std::vector<std::string> layouts;
layouts.push_back("us");
std::vector<std::string> languages;
languages.push_back("en-US");
const std::string ext1_id =
extension_ime_util::GetInputMethodID(kExtensionId1, "engine_id");
const InputMethodDescriptor descriptor1(ext1_id,
"deadbeef input method",
"DB",
layouts,
languages,
false, // is_login_keyboard
GURL(),
GURL());
MockInputMethodEngine engine;
InputMethodDescriptors descriptors;
descriptors.push_back(descriptor1);
manager_->GetActiveIMEState()->AddInputMethodExtension(
kExtensionId1, descriptors, &engine);
// Extension IMEs are not enabled by default.
EXPECT_EQ(1U, manager_->GetActiveIMEState()->GetNumActiveInputMethods());
std::vector<std::string> extension_ime_ids;
extension_ime_ids.push_back(ext1_id);
manager_->GetActiveIMEState()->SetEnabledExtensionImes(&extension_ime_ids);
EXPECT_EQ(2U, manager_->GetActiveIMEState()->GetNumActiveInputMethods());
{
std::unique_ptr<InputMethodDescriptors> methods(
manager_->GetActiveIMEState()->GetActiveInputMethods());
ASSERT_EQ(2U, methods->size());
// Ext IMEs should be at the end of the list.
EXPECT_EQ(ext1_id, methods->at(1).id());
}
const std::string ext2_id =
extension_ime_util::GetInputMethodID(kExtensionId2, "engine_id");
const InputMethodDescriptor descriptor2(ext2_id,
"cafebabe input method",
"CB",
layouts,
languages,
false, // is_login_keyboard
GURL(),
GURL());
descriptors.clear();
descriptors.push_back(descriptor2);
MockInputMethodEngine engine2;
manager_->GetActiveIMEState()->AddInputMethodExtension(
kExtensionId2, descriptors, &engine2);
EXPECT_EQ(2U, manager_->GetActiveIMEState()->GetNumActiveInputMethods());
extension_ime_ids.push_back(ext2_id);
manager_->GetActiveIMEState()->SetEnabledExtensionImes(&extension_ime_ids);
EXPECT_EQ(3U, manager_->GetActiveIMEState()->GetNumActiveInputMethods());
{
std::unique_ptr<InputMethodDescriptors> methods(
manager_->GetActiveIMEState()->GetActiveInputMethods());
ASSERT_EQ(3U, methods->size());
// Ext IMEs should be at the end of the list.
EXPECT_EQ(ext1_id, methods->at(1).id());
EXPECT_EQ(ext2_id, methods->at(2).id());
}
// Remove them.
manager_->GetActiveIMEState()->RemoveInputMethodExtension(kExtensionId1);
EXPECT_EQ(2U, manager_->GetActiveIMEState()->GetNumActiveInputMethods());
manager_->GetActiveIMEState()->RemoveInputMethodExtension(kExtensionId2);
EXPECT_EQ(1U, manager_->GetActiveIMEState()->GetNumActiveInputMethods());
}
TEST_F(InputMethodManagerImplTest, TestAddExtensionInputThenLockScreen) {
TestObserver observer;
InitComponentExtension();
manager_->AddObserver(&observer);
manager_->SetUISessionState(InputMethodManager::STATE_BROWSER_SCREEN);
std::vector<std::string> ids;
ids.push_back(ImeIdFromEngineId("xkb:us::eng"));
EXPECT_TRUE(manager_->GetActiveIMEState()->ReplaceEnabledInputMethods(ids));
EXPECT_EQ(1U, manager_->GetActiveIMEState()->GetNumActiveInputMethods());
EXPECT_EQ(1, observer.input_method_changed_count_);
EXPECT_EQ(ImeIdFromEngineId(ids[0]),
manager_->GetActiveIMEState()->GetCurrentInputMethod().id());
EXPECT_EQ("us", keyboard_->last_layout_);
// Add an Extension IME.
std::vector<std::string> layouts;
layouts.push_back("us(dvorak)");
std::vector<std::string> languages;
languages.push_back("en-US");
const std::string ext_id =
extension_ime_util::GetInputMethodID(kExtensionId1, "engine_id");
const InputMethodDescriptor descriptor(ext_id,
"deadbeef input method",
"DB",
layouts,
languages,
false, // is_login_keyboard
GURL(),
GURL());
MockInputMethodEngine engine;
InputMethodDescriptors descriptors;
descriptors.push_back(descriptor);
manager_->GetActiveIMEState()->AddInputMethodExtension(
kExtensionId1, descriptors, &engine);
// Extension IME is not enabled by default.
EXPECT_EQ(1U, manager_->GetActiveIMEState()->GetNumActiveInputMethods());
EXPECT_EQ(1, observer.input_method_changed_count_);
std::vector<std::string> extension_ime_ids;
extension_ime_ids.push_back(ext_id);
manager_->GetActiveIMEState()->SetEnabledExtensionImes(&extension_ime_ids);
EXPECT_EQ(2U, manager_->GetActiveIMEState()->GetNumActiveInputMethods());
// Switch to the IME.
manager_->GetActiveIMEState()->SwitchToNextInputMethod();
EXPECT_EQ(3, observer.input_method_changed_count_);
EXPECT_EQ(ext_id,
manager_->GetActiveIMEState()->GetCurrentInputMethod().id());
EXPECT_EQ("us(dvorak)", keyboard_->last_layout_);
// Lock the screen. This is for crosbug.com/27049.
scoped_refptr<input_method::InputMethodManager::State> saved_ime_state =
manager_->GetActiveIMEState();
manager_->SetState(saved_ime_state->Clone());
manager_->GetActiveIMEState()->EnableLockScreenLayouts();
manager_->SetUISessionState(InputMethodManager::STATE_LOCK_SCREEN);
EXPECT_EQ(1U,
manager_->GetActiveIMEState()
->GetNumActiveInputMethods()); // Qwerty. No Ext. IME
EXPECT_EQ(ImeIdFromEngineId("xkb:us::eng"),
manager_->GetActiveIMEState()->GetCurrentInputMethod().id());
EXPECT_EQ("us", keyboard_->last_layout_);
// Unlock the screen.
manager_->SetState(saved_ime_state);
manager_->SetUISessionState(InputMethodManager::STATE_BROWSER_SCREEN);
EXPECT_EQ(2U, manager_->GetActiveIMEState()->GetNumActiveInputMethods());
EXPECT_EQ(ext_id,
manager_->GetActiveIMEState()->GetCurrentInputMethod().id());
EXPECT_EQ("us(dvorak)", keyboard_->last_layout_);
{
// This is for crosbug.com/27052.
std::unique_ptr<InputMethodDescriptors> methods(
manager_->GetActiveIMEState()->GetActiveInputMethods());
ASSERT_EQ(2U, methods->size());
// Ext. IMEs should be at the end of the list.
EXPECT_EQ(ext_id, methods->at(1).id());
}
manager_->RemoveObserver(&observer);
}
TEST_F(InputMethodManagerImplTest,
ChangeInputMethod_ComponenteExtensionOneIME) {
InitComponentExtension();
manager_->SetUISessionState(InputMethodManager::STATE_BROWSER_SCREEN);
const std::string ext_id = extension_ime_util::GetComponentInputMethodID(
ime_list_[1].id,
ime_list_[1].engines[0].engine_id);
std::vector<std::string> ids;
ids.push_back(ext_id);
EXPECT_TRUE(manager_->GetActiveIMEState()->ReplaceEnabledInputMethods(ids));
EXPECT_EQ(1U, manager_->GetActiveIMEState()->GetNumActiveInputMethods());
EXPECT_EQ(ext_id,
manager_->GetActiveIMEState()->GetCurrentInputMethod().id());
}
TEST_F(InputMethodManagerImplTest,
ChangeInputMethod_ComponenteExtensionTwoIME) {
InitComponentExtension();
manager_->SetUISessionState(InputMethodManager::STATE_BROWSER_SCREEN);
const std::string ext_id1 = extension_ime_util::GetComponentInputMethodID(
ime_list_[1].id,
ime_list_[1].engines[0].engine_id);
const std::string ext_id2 = extension_ime_util::GetComponentInputMethodID(
ime_list_[2].id,
ime_list_[2].engines[0].engine_id);
std::vector<std::string> ids;
ids.push_back(ext_id1);
ids.push_back(ext_id2);
EXPECT_TRUE(manager_->GetActiveIMEState()->ReplaceEnabledInputMethods(ids));
EXPECT_EQ(2U, manager_->GetActiveIMEState()->GetNumActiveInputMethods());
EXPECT_EQ(ext_id1,
manager_->GetActiveIMEState()->GetCurrentInputMethod().id());
manager_->GetActiveIMEState()->ChangeInputMethod(ext_id2,
false /* show_message */);
EXPECT_EQ(ext_id2,
manager_->GetActiveIMEState()->GetCurrentInputMethod().id());
}
TEST_F(InputMethodManagerImplTest, MigrateInputMethodTest) {
std::vector<std::string> input_method_ids;
input_method_ids.push_back("xkb:us::eng");
input_method_ids.push_back("xkb:fr::fra");
input_method_ids.push_back(ImeIdFromEngineId("xkb:us::eng"));
input_method_ids.push_back("xkb:fr::fra");
input_method_ids.push_back(ImeIdFromEngineId("xkb:us::eng"));
input_method_ids.push_back("_comp_ime_asdf_pinyin");
input_method_ids.push_back(ImeIdFromEngineId(kPinyinImeId));
manager_->MigrateInputMethods(&input_method_ids);
ASSERT_EQ(4U, input_method_ids.size());
EXPECT_EQ(ImeIdFromEngineId("xkb:us::eng"), input_method_ids[0]);
EXPECT_EQ(ImeIdFromEngineId("xkb:fr::fra"), input_method_ids[1]);
EXPECT_EQ("_comp_ime_asdf_pinyin", input_method_ids[2]);
EXPECT_EQ(ImeIdFromEngineId("zh-t-i0-pinyin"), input_method_ids[3]);
}
TEST_F(InputMethodManagerImplTest, OverrideKeyboardUrlRefWithKeyset) {
InitComponentExtension();
const GURL inputview_url(
"chrome-extension://"
"inputview.html#id=us.compact.qwerty&language=en-US&passwordLayout=us."
"compact.qwerty&name=keyboard_us");
GetActiveIMEState()->input_view_url = inputview_url;
EXPECT_EQ(inputview_url, GetActiveIMEState()->GetInputViewUrl());
// Override the keyboard url ref with 'emoji'.
const GURL overridden_url_emoji(
"chrome-extension://"
"inputview.html#id=us.compact.qwerty.emoji&language=en-US&passwordLayout="
"us.compact.qwerty&name=keyboard_us");
manager_->OverrideKeyboardKeyset(mojom::ImeKeyset::kEmoji);
EXPECT_EQ(overridden_url_emoji, GetActiveIMEState()->GetInputViewUrl());
// Override the keyboard url ref with 'hwt'.
GetActiveIMEState()->input_view_url = inputview_url;
const GURL overridden_url_hwt(
"chrome-extension://"
"inputview.html#id=us.compact.qwerty.hwt&language=en-US&passwordLayout="
"us.compact.qwerty&name=keyboard_us");
manager_->OverrideKeyboardKeyset(mojom::ImeKeyset::kHandwriting);
EXPECT_EQ(overridden_url_hwt, GetActiveIMEState()->GetInputViewUrl());
// Override the keyboard url ref with 'voice'.
GetActiveIMEState()->input_view_url = inputview_url;
const GURL overridden_url_voice(
"chrome-extension://"
"inputview.html#id=us.compact.qwerty.voice&language=en-US"
"&passwordLayout=us.compact.qwerty&name=keyboard_us");
manager_->OverrideKeyboardKeyset(mojom::ImeKeyset::kVoice);
EXPECT_EQ(overridden_url_voice, GetActiveIMEState()->GetInputViewUrl());
}
TEST_F(InputMethodManagerImplTest, OverrideDefaultKeyboardUrlRef) {
InitComponentExtension();
const GURL default_url("chrome://inputview.html");
GetActiveIMEState()->input_view_url = default_url;
EXPECT_EQ(default_url, GetActiveIMEState()->GetInputViewUrl());
manager_->OverrideKeyboardKeyset(mojom::ImeKeyset::kEmoji);
EXPECT_EQ(default_url, GetActiveIMEState()->GetInputViewUrl());
}
TEST_F(InputMethodManagerImplTest, AllowedKeyboardLayoutsValid) {
InitComponentExtension();
// First, setup xkb:fr::fra input method
std::string original_input_method(ImeIdFromEngineId("xkb:fr::fra"));
ASSERT_TRUE(
manager_->GetActiveIMEState()->EnableInputMethod(original_input_method));
manager_->GetActiveIMEState()->ChangeInputMethod(original_input_method,
false);
EXPECT_THAT(manager_->GetActiveIMEState()->GetCurrentInputMethod().id(),
original_input_method);
// Only allow xkb:us::eng
std::vector<std::string> allowed = {"xkb:us::eng"};
EXPECT_TRUE(
manager_->GetActiveIMEState()->SetAllowedInputMethods(allowed, true));
EXPECT_THAT(manager_->GetActiveIMEState()->GetActiveInputMethodIds(),
testing::ElementsAre(ImeIdFromEngineId("xkb:us::eng")));
EXPECT_THAT(manager_->GetActiveIMEState()->GetCurrentInputMethod().id(),
ImeIdFromEngineId("xkb:us::eng"));
EXPECT_THAT(manager_->GetActiveIMEState()->GetAllowedInputMethods(),
testing::ElementsAre(ImeIdFromEngineId("xkb:us::eng")));
}
TEST_F(InputMethodManagerImplTest, AllowedKeyboardLayoutsInvalid) {
InitComponentExtension();
// First, setup xkb:fr::fra input method
std::string original_input_method(ImeIdFromEngineId("xkb:fr::fra"));
ASSERT_TRUE(
manager_->GetActiveIMEState()->EnableInputMethod(original_input_method));
manager_->GetActiveIMEState()->ChangeInputMethod(original_input_method,
false);
EXPECT_THAT(manager_->GetActiveIMEState()->GetCurrentInputMethod().id(),
original_input_method);
// Only allow xkb:us::eng
std::vector<std::string> allowed = {"invalid_input_method"};
EXPECT_FALSE(
manager_->GetActiveIMEState()->SetAllowedInputMethods(allowed, true));
EXPECT_THAT(manager_->GetActiveIMEState()->GetCurrentInputMethod().id(),
original_input_method);
EXPECT_THAT(manager_->GetActiveIMEState()->GetAllowedInputMethods(),
testing::IsEmpty());
}
TEST_F(InputMethodManagerImplTest, AllowedKeyboardLayoutsValidAndInvalid) {
InitComponentExtension();
// First, enable xkb:fr::fra and xkb:de::ger
std::string original_input_method_1(ImeIdFromEngineId("xkb:fr::fra"));
std::string original_input_method_2(ImeIdFromEngineId("xkb:de::ger"));
ASSERT_TRUE(manager_->GetActiveIMEState()->EnableInputMethod(
original_input_method_1));
ASSERT_TRUE(manager_->GetActiveIMEState()->EnableInputMethod(
original_input_method_2));
manager_->GetActiveIMEState()->ChangeInputMethod(original_input_method_1,
false);
// Allow xkb:fr::fra and an invalid input method id. The invalid id should be
// ignored.
std::vector<std::string> allowed = {original_input_method_1,
"invalid_input_method"};
EXPECT_TRUE(
manager_->GetActiveIMEState()->SetAllowedInputMethods(allowed, true));
EXPECT_THAT(manager_->GetActiveIMEState()->GetCurrentInputMethod().id(),
original_input_method_1);
EXPECT_THAT(manager_->GetActiveIMEState()->GetAllowedInputMethods(),
testing::ElementsAre(original_input_method_1));
// Try to re-enable xkb:de::ger
EXPECT_FALSE(manager_->GetActiveIMEState()->EnableInputMethod(
original_input_method_2));
}
TEST_F(InputMethodManagerImplTest, AllowedKeyboardLayoutsAndExtensions) {
InitComponentExtension();
EXPECT_TRUE(manager_->GetActiveIMEState()->EnableInputMethod(
ImeIdFromEngineId(kNaclMozcJpId)));
EXPECT_TRUE(manager_->GetActiveIMEState()->EnableInputMethod(
ImeIdFromEngineId("xkb:fr::fra")));
std::vector<std::string> allowed = {"xkb:us::eng"};
EXPECT_TRUE(
manager_->GetActiveIMEState()->SetAllowedInputMethods(allowed, true));
EXPECT_TRUE(manager_->GetActiveIMEState()->EnableInputMethod(
ImeIdFromEngineId(kNaclMozcUsId)));
EXPECT_THAT(manager_->GetActiveIMEState()->GetActiveInputMethodIds(),
testing::ElementsAre(ImeIdFromEngineId("xkb:us::eng"),
ImeIdFromEngineId(kNaclMozcJpId),
ImeIdFromEngineId(kNaclMozcUsId)));
}
TEST_F(InputMethodManagerImplTest, SetLoginDefaultWithAllowedKeyboardLayouts) {
InitComponentExtension();
std::vector<std::string> allowed = {"xkb:us::eng", "xkb:de::ger",
"xkb:fr::fra"};
EXPECT_TRUE(
manager_->GetActiveIMEState()->SetAllowedInputMethods(allowed, true));
manager_->GetActiveIMEState()->SetInputMethodLoginDefault();
EXPECT_THAT(manager_->GetActiveIMEState()->GetActiveInputMethodIds(),
testing::ElementsAre(ImeIdFromEngineId("xkb:us::eng"),
ImeIdFromEngineId("xkb:de::ger"),
ImeIdFromEngineId("xkb:fr::fra")));
}
// Verifies that the combination of InputMethodManagerImpl and
// ImeControllerClient sends the correct data to ash.
TEST_F(InputMethodManagerImplTest, IntegrationWithAsh) {
TestImeController ime_controller; // Mojo interface to ash.
ImeControllerClient ime_controller_client(manager_.get());
ime_controller_client.InitForTesting(ime_controller.CreateInterfacePtr());
// Setup 3 IMEs.
InitComponentExtension();
manager_->SetUISessionState(InputMethodManager::STATE_BROWSER_SCREEN);
std::vector<std::string> ids;
ids.push_back(ImeIdFromEngineId("xkb:us:dvorak:eng"));
ids.push_back(ImeIdFromEngineId(kExt2Engine2Id));
ids.push_back(ImeIdFromEngineId(kExt2Engine1Id));
manager_->GetActiveIMEState()->ReplaceEnabledInputMethods(ids);
ime_controller_client.FlushMojoForTesting();
// Ash received the IMEs.
ASSERT_EQ(3u, ime_controller.available_imes_.size());
EXPECT_EQ(ImeIdFromEngineId(ids[0]), ime_controller.current_ime_id_);
// Switch to Mozc.
manager_->GetActiveIMEState()->SwitchToNextInputMethod();
ime_controller_client.FlushMojoForTesting();
EXPECT_EQ(ImeIdFromEngineId(ids[1]), ime_controller.current_ime_id_);
// Lock the screen.
scoped_refptr<input_method::InputMethodManager::State> saved_ime_state =
manager_->GetActiveIMEState();
manager_->SetState(saved_ime_state->Clone());
manager_->GetActiveIMEState()->EnableLockScreenLayouts();
manager_->SetUISessionState(InputMethodManager::STATE_LOCK_SCREEN);
ime_controller_client.FlushMojoForTesting();
EXPECT_EQ(2u, ime_controller.available_imes_.size()); // Qwerty+Dvorak.
EXPECT_EQ(ImeIdFromEngineId("xkb:us:dvorak:eng"),
ime_controller.current_ime_id_);
manager_->GetActiveIMEState()->SwitchToNextInputMethod();
ime_controller_client.FlushMojoForTesting();
EXPECT_EQ(ImeIdFromEngineId("xkb:us::eng"), // The hardware keyboard layout.
ime_controller.current_ime_id_);
// Unlock screen. The original state, pinyin-dv, is restored.
manager_->SetState(saved_ime_state);
manager_->SetUISessionState(InputMethodManager::STATE_BROWSER_SCREEN);
ime_controller_client.FlushMojoForTesting();
ASSERT_EQ(3u, ime_controller.available_imes_.size()); // Dvorak and 2 IMEs.
EXPECT_EQ(ImeIdFromEngineId(ids[1]), ime_controller.current_ime_id_);
}
TEST_F(InputMethodManagerImplTest, SetFeaturesDisabled) {
// All features are enabled by default.
EXPECT_TRUE(
manager_->GetImeMenuFeatureEnabled(InputMethodManager::FEATURE_ALL));
EXPECT_TRUE(
manager_->GetImeMenuFeatureEnabled(InputMethodManager::FEATURE_EMOJI));
EXPECT_TRUE(manager_->GetImeMenuFeatureEnabled(
InputMethodManager::FEATURE_HANDWRITING));
EXPECT_TRUE(
manager_->GetImeMenuFeatureEnabled(InputMethodManager::FEATURE_VOICE));
// Sets emoji disabled and then enabled.
manager_->SetImeMenuFeatureEnabled(InputMethodManager::FEATURE_EMOJI, false);
EXPECT_FALSE(
manager_->GetImeMenuFeatureEnabled(InputMethodManager::FEATURE_EMOJI));
manager_->SetImeMenuFeatureEnabled(InputMethodManager::FEATURE_EMOJI, true);
EXPECT_TRUE(
manager_->GetImeMenuFeatureEnabled(InputMethodManager::FEATURE_EMOJI));
// Sets voice disabled and then enabled.
manager_->SetImeMenuFeatureEnabled(InputMethodManager::FEATURE_VOICE, false);
EXPECT_FALSE(
manager_->GetImeMenuFeatureEnabled(InputMethodManager::FEATURE_VOICE));
manager_->SetImeMenuFeatureEnabled(InputMethodManager::FEATURE_VOICE, true);
EXPECT_TRUE(
manager_->GetImeMenuFeatureEnabled(InputMethodManager::FEATURE_VOICE));
// Sets handwriting disabled and then enabled.
manager_->SetImeMenuFeatureEnabled(InputMethodManager::FEATURE_HANDWRITING,
false);
EXPECT_FALSE(manager_->GetImeMenuFeatureEnabled(
InputMethodManager::FEATURE_HANDWRITING));
manager_->SetImeMenuFeatureEnabled(InputMethodManager::FEATURE_HANDWRITING,
true);
EXPECT_TRUE(manager_->GetImeMenuFeatureEnabled(
InputMethodManager::FEATURE_HANDWRITING));
}
TEST_F(InputMethodManagerImplTest, TestAddRemoveArcInputMethods) {
InitComponentExtension();
manager_->SetUISessionState(InputMethodManager::STATE_BROWSER_SCREEN);
// There is one default IME
EXPECT_EQ(1u, manager_->GetActiveIMEState()->GetNumActiveInputMethods());
// Add an ARC IMEs.
std::vector<std::string> layouts({"us"});
std::vector<std::string> languages({"en-US"});
MockInputMethodEngine engine;
const std::string ime_id =
extension_ime_util::GetArcInputMethodID(kExtensionId1, "engine_id");
const InputMethodDescriptor descriptor(
ime_id, "arc ime", "AI", layouts, languages,
false /* is_login_keyboard */, GURL(), GURL());
InputMethodDescriptors descriptors({descriptor});
manager_->GetActiveIMEState()->AddInputMethodExtension(kExtensionId1,
descriptors, &engine);
InputMethodDescriptors result;
manager_->GetActiveIMEState()->GetInputMethodExtensions(&result);
EXPECT_EQ(1u, result.size());
EXPECT_EQ(ime_id, result[0].id());
result.clear();
// The ARC IME is not enabled by default.
EXPECT_EQ(1u, manager_->GetActiveIMEState()->GetNumActiveInputMethods());
// Enable it.
std::vector<std::string> extension_ime_ids({ime_id});
manager_->GetActiveIMEState()->SetEnabledExtensionImes(&extension_ime_ids);
EXPECT_EQ(2u, manager_->GetActiveIMEState()->GetNumActiveInputMethods());
{
std::unique_ptr<InputMethodDescriptors> methods =
manager_->GetActiveIMEState()->GetActiveInputMethods();
EXPECT_EQ(2u, methods->size());
EXPECT_EQ(ime_id, methods->at(1).id());
}
// Change to it.
manager_->GetActiveIMEState()->ChangeInputMethod(ime_id,
false /* show_message */);
InputMethodDescriptor current =
manager_->GetActiveIMEState()->GetCurrentInputMethod();
EXPECT_EQ(ime_id, current.id());
// Remove it.
manager_->GetActiveIMEState()->RemoveInputMethodExtension(kExtensionId1);
manager_->GetActiveIMEState()->GetInputMethodExtensions(&result);
EXPECT_TRUE(result.empty());
}
} // namespace input_method
} // namespace chromeos