1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #include "chrome/browser/chromeos/input_method/input_method_manager_impl.h"
9 #include "ash/ime/input_method_menu_item.h"
10 #include "ash/ime/input_method_menu_manager.h"
11 #include "base/basictypes.h"
12 #include "base/bind.h"
13 #include "base/bind_helpers.h"
14 #include "base/compiler_specific.h"
15 #include "base/logging.h"
16 #include "base/memory/scoped_ptr.h"
17 #include "base/message_loop/message_loop.h"
18 #include "base/run_loop.h"
19 #include "chrome/browser/chromeos/input_method/input_method_engine_interface.h"
20 #include "chrome/browser/chromeos/input_method/mock_candidate_window_controller.h"
21 #include "chrome/browser/chromeos/input_method/mock_input_method_engine.h"
22 #include "chrome/test/base/browser_with_test_window_test.h"
23 #include "chrome/test/base/testing_browser_process.h"
24 #include "chrome/test/base/testing_profile.h"
25 #include "chrome/test/base/testing_profile_manager.h"
26 #include "chromeos/ime/extension_ime_util.h"
27 #include "chromeos/ime/fake_ime_keyboard.h"
28 #include "chromeos/ime/fake_input_method_delegate.h"
29 #include "chromeos/ime/mock_component_extension_ime_manager_delegate.h"
30 #include "testing/gtest/include/gtest/gtest.h"
31 #include "ui/base/accelerators/accelerator.h"
32 #include "ui/base/ime/chromeos/mock_ime_engine_handler.h"
33 #include "ui/base/ime/input_method_initializer.h"
34 #include "ui/events/keycodes/keyboard_codes.h"
38 namespace input_method {
41 const char kNaclMozcUsId[] = "nacl_mozc_us";
42 const char kNaclMozcJpId[] = "nacl_mozc_jp";
43 const char kExt2Engine1Id[] = "ext2_engine1-t-i0-engine_id";
44 const char kExt2Engine2Id[] = "ext2_engine2-t-i0-engine_id";
45 const char kPinyinImeId[] = "zh-t-i0-pinyin";
46 const char kExtensionId1[] = "00000000000000000000000000000000";
47 const char kExtensionId2[] = "11111111111111111111111111111111";
49 // Returns true if |descriptors| contain |target|.
50 bool Contain(const InputMethodDescriptors& descriptors,
51 const InputMethodDescriptor& target) {
52 for (size_t i = 0; i < descriptors.size(); ++i) {
53 if (descriptors[i].id() == target.id())
59 std::string ImeIdFromEngineId(const std::string& id) {
60 return extension_ime_util::GetInputMethodIDByEngineID(id);
63 class TestObserver : public InputMethodManager::Observer,
64 public ash::ime::InputMethodMenuManager::Observer {
67 : input_method_changed_count_(0),
68 input_method_menu_item_changed_count_(0),
69 last_show_message_(false) {
71 virtual ~TestObserver() {}
73 virtual void InputMethodChanged(InputMethodManager* manager,
74 bool show_message) OVERRIDE {
75 ++input_method_changed_count_;
76 last_show_message_ = show_message;
78 virtual void InputMethodMenuItemChanged(
79 ash::ime::InputMethodMenuManager* manager) OVERRIDE {
80 ++input_method_menu_item_changed_count_;
83 int input_method_changed_count_;
84 int input_method_menu_item_changed_count_;
85 bool last_show_message_;
88 DISALLOW_COPY_AND_ASSIGN(TestObserver);
91 class TestCandidateWindowObserver
92 : public InputMethodManager::CandidateWindowObserver {
94 TestCandidateWindowObserver()
95 : candidate_window_opened_count_(0),
96 candidate_window_closed_count_(0) {
99 virtual ~TestCandidateWindowObserver() {}
101 virtual void CandidateWindowOpened(InputMethodManager* manager) OVERRIDE {
102 ++candidate_window_opened_count_;
104 virtual void CandidateWindowClosed(InputMethodManager* manager) OVERRIDE {
105 ++candidate_window_closed_count_;
108 int candidate_window_opened_count_;
109 int candidate_window_closed_count_;
112 DISALLOW_COPY_AND_ASSIGN(TestCandidateWindowObserver);
116 class InputMethodManagerImplTest : public BrowserWithTestWindowTest {
118 InputMethodManagerImplTest()
120 candidate_window_controller_(NULL),
123 virtual ~InputMethodManagerImplTest() {}
125 virtual void SetUp() OVERRIDE {
126 profile_manager_.reset(new TestingProfileManager(GetBrowserProcess()));
127 ASSERT_TRUE(profile_manager_->SetUp());
129 ui::InitializeInputMethodForTesting();
131 delegate_ = new FakeInputMethodDelegate();
132 manager_.reset(new InputMethodManagerImpl(
133 scoped_ptr<InputMethodDelegate>(delegate_), false));
134 manager_->GetInputMethodUtil()->UpdateHardwareLayoutCache();
135 candidate_window_controller_ = new MockCandidateWindowController;
136 manager_->SetCandidateWindowControllerForTesting(
137 candidate_window_controller_);
138 keyboard_ = new FakeImeKeyboard;
139 manager_->SetImeKeyboardForTesting(keyboard_);
140 mock_engine_handler_.reset(new MockInputMethodEngine());
141 IMEBridge::Initialize();
142 IMEBridge::Get()->SetCurrentEngineHandler(mock_engine_handler_.get());
144 menu_manager_ = ash::ime::InputMethodMenuManager::GetInstance();
148 BrowserWithTestWindowTest::SetUp();
151 virtual void TearDown() OVERRIDE {
152 BrowserWithTestWindowTest::TearDown();
154 ui::ShutdownInputMethodForTesting();
157 candidate_window_controller_ = NULL;
161 profile_manager_.reset();
165 // Helper function to initialize component extension stuff for testing.
166 void InitComponentExtension() {
167 mock_delegate_ = new MockComponentExtIMEManagerDelegate();
168 mock_delegate_->set_ime_list(ime_list_);
169 scoped_ptr<ComponentExtensionIMEManagerDelegate> delegate(mock_delegate_);
171 std::vector<std::string> layouts;
172 layouts.push_back("us");
173 std::vector<std::string> languages;
174 languages.push_back("en-US");
176 // Note, for production, these SetEngineHandler are called when
177 // IMEEngineHandlerInterface is initialized via
178 // InitializeComponentextension.
179 InputMethodDescriptors descriptors;
180 manager_->AddInputMethodExtension(ImeIdFromEngineId(kNaclMozcUsId),
182 mock_engine_handler_.get());
183 manager_->AddInputMethodExtension(ImeIdFromEngineId(kExt2Engine1Id),
185 mock_engine_handler_.get());
186 manager_->InitializeComponentExtensionForTesting(delegate.Pass());
192 ComponentExtensionIME ext_xkb;
193 ext_xkb.id = extension_ime_util::kXkbExtensionId;
194 ext_xkb.description = "ext_xkb_description";
195 ext_xkb.path = base::FilePath("ext_xkb_file_path");
197 ComponentExtensionEngine ext_xkb_engine_us;
198 ext_xkb_engine_us.engine_id = "xkb:us::eng";
199 ext_xkb_engine_us.display_name = "xkb:us::eng";
200 ext_xkb_engine_us.language_codes.push_back("en-US");
201 ext_xkb_engine_us.layouts.push_back("us");
202 ext_xkb.engines.push_back(ext_xkb_engine_us);
204 ComponentExtensionEngine ext_xkb_engine_intl;
205 ext_xkb_engine_intl.engine_id = "xkb:us:intl:eng";
206 ext_xkb_engine_intl.display_name = "xkb:us:intl:eng";
207 ext_xkb_engine_intl.language_codes.push_back("en-US");
208 ext_xkb_engine_intl.layouts.push_back("us(intl)");
209 ext_xkb.engines.push_back(ext_xkb_engine_intl);
211 ComponentExtensionEngine ext_xkb_engine_altgr_intl;
212 ext_xkb_engine_altgr_intl.engine_id = "xkb:us:altgr-intl:eng";
213 ext_xkb_engine_altgr_intl.display_name = "xkb:us:altgr-intl:eng";
214 ext_xkb_engine_altgr_intl.language_codes.push_back("en-US");
215 ext_xkb_engine_altgr_intl.layouts.push_back("us(altgr-intl)");
216 ext_xkb.engines.push_back(ext_xkb_engine_altgr_intl);
218 ComponentExtensionEngine ext_xkb_engine_dvorak;
219 ext_xkb_engine_dvorak.engine_id = "xkb:us:dvorak:eng";
220 ext_xkb_engine_dvorak.display_name = "xkb:us:dvorak:eng";
221 ext_xkb_engine_dvorak.language_codes.push_back("en-US");
222 ext_xkb_engine_dvorak.layouts.push_back("us(dvorak)");
223 ext_xkb.engines.push_back(ext_xkb_engine_dvorak);
225 ComponentExtensionEngine ext_xkb_engine_colemak;
226 ext_xkb_engine_colemak.engine_id = "xkb:us:colemak:eng";
227 ext_xkb_engine_colemak.display_name = "xkb:us:colemak:eng";
228 ext_xkb_engine_colemak.language_codes.push_back("en-US");
229 ext_xkb_engine_colemak.layouts.push_back("us(colemak)");
230 ext_xkb.engines.push_back(ext_xkb_engine_colemak);
232 ComponentExtensionEngine ext_xkb_engine_fr;
233 ext_xkb_engine_fr.engine_id = "xkb:fr::fra";
234 ext_xkb_engine_fr.display_name = "xkb:fr::fra";
235 ext_xkb_engine_fr.language_codes.push_back("fr");
236 ext_xkb_engine_fr.layouts.push_back("fr");
237 ext_xkb.engines.push_back(ext_xkb_engine_fr);
239 ComponentExtensionEngine ext_xkb_engine_se;
240 ext_xkb_engine_se.engine_id = "xkb:se::swe";
241 ext_xkb_engine_se.display_name = "xkb:se::swe";
242 ext_xkb_engine_se.language_codes.push_back("sv");
243 ext_xkb_engine_se.layouts.push_back("se");
244 ext_xkb.engines.push_back(ext_xkb_engine_se);
246 ComponentExtensionEngine ext_xkb_engine_jp;
247 ext_xkb_engine_jp.engine_id = "xkb:jp::jpn";
248 ext_xkb_engine_jp.display_name = "xkb:jp::jpn";
249 ext_xkb_engine_jp.language_codes.push_back("ja");
250 ext_xkb_engine_jp.layouts.push_back("jp");
251 ext_xkb.engines.push_back(ext_xkb_engine_jp);
253 ComponentExtensionEngine ext_xkb_engine_ru;
254 ext_xkb_engine_ru.engine_id = "xkb:ru::rus";
255 ext_xkb_engine_ru.display_name = "xkb:ru::rus";
256 ext_xkb_engine_ru.language_codes.push_back("ru");
257 ext_xkb_engine_ru.layouts.push_back("ru");
258 ext_xkb.engines.push_back(ext_xkb_engine_ru);
260 ComponentExtensionEngine ext_xkb_engine_hu;
261 ext_xkb_engine_hu.engine_id = "xkb:hu::hun";
262 ext_xkb_engine_hu.display_name = "xkb:hu::hun";
263 ext_xkb_engine_hu.language_codes.push_back("hu");
264 ext_xkb_engine_hu.layouts.push_back("hu");
265 ext_xkb.engines.push_back(ext_xkb_engine_hu);
267 ime_list_.push_back(ext_xkb);
269 ComponentExtensionIME ext1;
270 ext1.id = extension_ime_util::kMozcExtensionId;
271 ext1.description = "ext1_description";
272 ext1.path = base::FilePath("ext1_file_path");
274 ComponentExtensionEngine ext1_engine1;
275 ext1_engine1.engine_id = "nacl_mozc_us";
276 ext1_engine1.display_name = "ext1_engine_1_display_name";
277 ext1_engine1.language_codes.push_back("ja");
278 ext1_engine1.layouts.push_back("us");
279 ext1.engines.push_back(ext1_engine1);
281 ComponentExtensionEngine ext1_engine2;
282 ext1_engine2.engine_id = "nacl_mozc_jp";
283 ext1_engine2.display_name = "ext1_engine_1_display_name";
284 ext1_engine2.language_codes.push_back("ja");
285 ext1_engine2.layouts.push_back("jp");
286 ext1.engines.push_back(ext1_engine2);
288 ime_list_.push_back(ext1);
290 ComponentExtensionIME ext2;
291 ext2.id = extension_ime_util::kT13nExtensionId;
292 ext2.description = "ext2_description";
293 ext2.path = base::FilePath("ext2_file_path");
295 ComponentExtensionEngine ext2_engine1;
296 ext2_engine1.engine_id = kExt2Engine1Id;
297 ext2_engine1.display_name = "ext2_engine_1_display_name";
298 ext2_engine1.language_codes.push_back("en");
299 ext2_engine1.layouts.push_back("us");
300 ext2.engines.push_back(ext2_engine1);
302 ComponentExtensionEngine ext2_engine2;
303 ext2_engine2.engine_id = kExt2Engine2Id;
304 ext2_engine2.display_name = "ext2_engine_2_display_name";
305 ext2_engine2.language_codes.push_back("en");
306 ext2_engine2.layouts.push_back("us(dvorak)");
307 ext2.engines.push_back(ext2_engine2);
309 ime_list_.push_back(ext2);
312 TestingBrowserProcess* GetBrowserProcess() {
313 return TestingBrowserProcess::GetGlobal();
316 scoped_ptr<TestingProfileManager> profile_manager_;
317 scoped_ptr<InputMethodManagerImpl> manager_;
318 FakeInputMethodDelegate* delegate_;
319 MockCandidateWindowController* candidate_window_controller_;
320 scoped_ptr<MockInputMethodEngine> mock_engine_handler_;
321 FakeImeKeyboard* keyboard_;
322 MockComponentExtIMEManagerDelegate* mock_delegate_;
323 std::vector<ComponentExtensionIME> ime_list_;
324 ash::ime::InputMethodMenuManager* menu_manager_;
327 DISALLOW_COPY_AND_ASSIGN(InputMethodManagerImplTest);
330 TEST_F(InputMethodManagerImplTest, TestGetImeKeyboard) {
331 EXPECT_TRUE(manager_->GetImeKeyboard());
332 EXPECT_EQ(keyboard_, manager_->GetImeKeyboard());
335 TEST_F(InputMethodManagerImplTest, TestCandidateWindowObserver) {
336 TestCandidateWindowObserver observer;
337 candidate_window_controller_->NotifyCandidateWindowOpened(); // nop
338 candidate_window_controller_->NotifyCandidateWindowClosed(); // nop
339 manager_->AddCandidateWindowObserver(&observer);
340 candidate_window_controller_->NotifyCandidateWindowOpened();
341 EXPECT_EQ(1, observer.candidate_window_opened_count_);
342 candidate_window_controller_->NotifyCandidateWindowClosed();
343 EXPECT_EQ(1, observer.candidate_window_closed_count_);
344 candidate_window_controller_->NotifyCandidateWindowOpened();
345 EXPECT_EQ(2, observer.candidate_window_opened_count_);
346 candidate_window_controller_->NotifyCandidateWindowClosed();
347 EXPECT_EQ(2, observer.candidate_window_closed_count_);
348 manager_->RemoveCandidateWindowObserver(&observer);
351 TEST_F(InputMethodManagerImplTest, TestObserver) {
352 // For http://crbug.com/19655#c11 - (3). browser_state_monitor_unittest.cc is
353 // also for the scenario.
354 std::vector<std::string> keyboard_layouts;
355 keyboard_layouts.push_back("xkb:us::eng");
357 TestObserver observer;
358 InitComponentExtension();
359 manager_->AddObserver(&observer);
360 menu_manager_->AddObserver(&observer);
361 EXPECT_EQ(0, observer.input_method_changed_count_);
362 manager_->EnableLoginLayouts("en-US", keyboard_layouts);
363 EXPECT_EQ(5U, manager_->GetActiveInputMethods()->size());
364 EXPECT_EQ(1, observer.input_method_changed_count_);
365 EXPECT_EQ(1, observer.input_method_menu_item_changed_count_);
366 manager_->ChangeInputMethod(ImeIdFromEngineId("xkb:us:dvorak:eng"));
367 EXPECT_FALSE(observer.last_show_message_);
368 EXPECT_EQ(2, observer.input_method_changed_count_);
369 EXPECT_EQ(2, observer.input_method_menu_item_changed_count_);
370 manager_->ChangeInputMethod(ImeIdFromEngineId("xkb:us:dvorak:eng"));
371 EXPECT_FALSE(observer.last_show_message_);
373 // The observer is always notified even when the same input method ID is
374 // passed to ChangeInputMethod() more than twice.
375 // TODO(komatsu): Revisit if this is neccessary.
376 EXPECT_EQ(3, observer.input_method_changed_count_);
378 // If the same input method ID is passed, PropertyChanged() is not
380 EXPECT_EQ(2, observer.input_method_menu_item_changed_count_);
382 manager_->RemoveObserver(&observer);
383 menu_manager_->RemoveObserver(&observer);
386 TEST_F(InputMethodManagerImplTest, TestGetSupportedInputMethods) {
387 InitComponentExtension();
388 InputMethodDescriptors methods;
389 methods = manager_->GetComponentExtensionIMEManager()
390 ->GetXkbIMEAsInputMethodDescriptor();
391 // Try to find random 4-5 layuts and IMEs to make sure the returned list is
393 const InputMethodDescriptor* id_to_find =
394 manager_->GetInputMethodUtil()->GetInputMethodDescriptorFromId(
395 ImeIdFromEngineId(kNaclMozcUsId));
396 id_to_find = manager_->GetInputMethodUtil()->GetInputMethodDescriptorFromId(
397 ImeIdFromEngineId("xkb:us::eng"));
398 EXPECT_TRUE(Contain(methods, *id_to_find));
399 id_to_find = manager_->GetInputMethodUtil()->GetInputMethodDescriptorFromId(
400 ImeIdFromEngineId("xkb:us:dvorak:eng"));
401 EXPECT_TRUE(Contain(methods, *id_to_find));
402 id_to_find = manager_->GetInputMethodUtil()->GetInputMethodDescriptorFromId(
403 ImeIdFromEngineId("xkb:fr::fra"));
404 EXPECT_TRUE(Contain(methods, *id_to_find));
407 TEST_F(InputMethodManagerImplTest, TestEnableLayouts) {
408 // Currently 5 keyboard layouts are supported for en-US, and 1 for ja. See
409 // ibus_input_method.txt.
410 std::vector<std::string> keyboard_layouts;
412 InitComponentExtension();
413 manager_->EnableLoginLayouts("en-US", keyboard_layouts);
414 EXPECT_EQ(5U, manager_->GetNumActiveInputMethods());
416 // For http://crbug.com/19655#c11 - (5)
417 // The hardware keyboard layout "xkb:us::eng" is always active, hence 2U.
418 manager_->EnableLoginLayouts("ja", keyboard_layouts); // Japanese
419 EXPECT_EQ(2U, manager_->GetNumActiveInputMethods());
422 TEST_F(InputMethodManagerImplTest, TestEnableLayoutsAndCurrentInputMethod) {
423 // For http://crbug.com/329061
424 std::vector<std::string> keyboard_layouts;
425 keyboard_layouts.push_back(ImeIdFromEngineId("xkb:se::swe"));
427 InitComponentExtension();
428 manager_->EnableLoginLayouts("en-US", keyboard_layouts);
429 const std::string im_id = manager_->GetCurrentInputMethod().id();
430 EXPECT_EQ(ImeIdFromEngineId("xkb:se::swe"), im_id);
433 TEST_F(InputMethodManagerImplTest, TestEnableLayoutsNonUsHardwareKeyboard) {
434 InitComponentExtension();
435 // The physical layout is French.
436 manager_->GetInputMethodUtil()->SetHardwareKeyboardLayoutForTesting(
438 manager_->EnableLoginLayouts(
440 manager_->GetInputMethodUtil()->GetHardwareLoginInputMethodIds());
441 EXPECT_EQ(6U, manager_->GetNumActiveInputMethods()); // 5 + French
442 // The physical layout is Japanese.
443 manager_->GetInputMethodUtil()->SetHardwareKeyboardLayoutForTesting(
445 manager_->EnableLoginLayouts(
447 manager_->GetInputMethodUtil()->GetHardwareLoginInputMethodIds());
448 // "xkb:us::eng" is not needed, hence 1.
449 EXPECT_EQ(1U, manager_->GetNumActiveInputMethods());
451 // The physical layout is Russian.
452 manager_->GetInputMethodUtil()->SetHardwareKeyboardLayoutForTesting(
454 manager_->EnableLoginLayouts(
456 manager_->GetInputMethodUtil()->GetHardwareLoginInputMethodIds());
457 // "xkb:us::eng" only.
458 EXPECT_EQ(1U, manager_->GetNumActiveInputMethods());
459 EXPECT_EQ(ImeIdFromEngineId("xkb:us::eng"),
460 manager_->GetActiveInputMethodIds().front());
463 TEST_F(InputMethodManagerImplTest, TestEnableMultipleHardwareKeyboardLayout) {
464 InitComponentExtension();
465 // The physical layouts are French and Hungarian.
466 manager_->GetInputMethodUtil()->SetHardwareKeyboardLayoutForTesting(
467 "xkb:fr::fra,xkb:hu::hun");
468 manager_->EnableLoginLayouts(
470 manager_->GetInputMethodUtil()->GetHardwareLoginInputMethodIds());
471 // 5 + French + Hungarian
472 EXPECT_EQ(7U, manager_->GetNumActiveInputMethods());
475 TEST_F(InputMethodManagerImplTest,
476 TestEnableMultipleHardwareKeyboardLayout_NoLoginKeyboard) {
477 InitComponentExtension();
478 // The physical layouts are English (US) and Russian.
479 manager_->GetInputMethodUtil()->SetHardwareKeyboardLayoutForTesting(
480 "xkb:us::eng,xkb:ru::rus");
481 manager_->EnableLoginLayouts(
483 manager_->GetInputMethodUtil()->GetHardwareLoginInputMethodIds());
485 EXPECT_EQ(1U, manager_->GetNumActiveInputMethods());
488 TEST_F(InputMethodManagerImplTest, TestActiveInputMethods) {
489 InitComponentExtension();
490 std::vector<std::string> keyboard_layouts;
491 manager_->EnableLoginLayouts("ja", keyboard_layouts); // Japanese
492 EXPECT_EQ(2U, manager_->GetNumActiveInputMethods());
493 scoped_ptr<InputMethodDescriptors> methods(
494 manager_->GetActiveInputMethods());
495 ASSERT_TRUE(methods.get());
496 EXPECT_EQ(2U, methods->size());
497 const InputMethodDescriptor* id_to_find =
498 manager_->GetInputMethodUtil()->GetInputMethodDescriptorFromId(
499 ImeIdFromEngineId("xkb:us::eng"));
500 EXPECT_TRUE(id_to_find && Contain(*methods.get(), *id_to_find));
501 id_to_find = manager_->GetInputMethodUtil()->GetInputMethodDescriptorFromId(
502 ImeIdFromEngineId("xkb:jp::jpn"));
503 EXPECT_TRUE(id_to_find && Contain(*methods.get(), *id_to_find));
506 TEST_F(InputMethodManagerImplTest, TestEnableTwoLayouts) {
507 // For http://crbug.com/19655#c11 - (8), step 6.
508 TestObserver observer;
509 manager_->AddObserver(&observer);
510 InitComponentExtension();
511 manager_->SetState(InputMethodManager::STATE_BROWSER_SCREEN);
512 std::vector<std::string> ids;
513 ids.push_back(ImeIdFromEngineId("xkb:us:dvorak:eng"));
514 ids.push_back(ImeIdFromEngineId("xkb:us:colemak:eng"));
515 EXPECT_TRUE(manager_->ReplaceEnabledInputMethods(ids));
516 EXPECT_EQ(2U, manager_->GetNumActiveInputMethods());
517 // Since all the IDs added avobe are keyboard layouts, Start() should not be
519 EXPECT_EQ(1, observer.input_method_changed_count_);
520 EXPECT_EQ(ImeIdFromEngineId(ids[0]), manager_->GetCurrentInputMethod().id());
521 EXPECT_EQ("us(dvorak)", keyboard_->last_layout_);
523 ids.erase(ids.begin());
524 EXPECT_TRUE(manager_->ReplaceEnabledInputMethods(ids));
525 EXPECT_EQ(1U, manager_->GetNumActiveInputMethods());
526 EXPECT_EQ(2, observer.input_method_changed_count_);
527 EXPECT_EQ(ImeIdFromEngineId(ids[0]), // colemak
528 manager_->GetCurrentInputMethod().id());
529 EXPECT_EQ("us(colemak)", keyboard_->last_layout_);
530 manager_->RemoveObserver(&observer);
533 TEST_F(InputMethodManagerImplTest, TestEnableThreeLayouts) {
534 // For http://crbug.com/19655#c11 - (9).
535 TestObserver observer;
536 manager_->AddObserver(&observer);
537 InitComponentExtension();
538 manager_->SetState(InputMethodManager::STATE_BROWSER_SCREEN);
539 std::vector<std::string> ids;
540 ids.push_back(ImeIdFromEngineId("xkb:us::eng"));
541 ids.push_back(ImeIdFromEngineId("xkb:us:dvorak:eng"));
542 ids.push_back(ImeIdFromEngineId("xkb:us:colemak:eng"));
543 EXPECT_TRUE(manager_->ReplaceEnabledInputMethods(ids));
544 EXPECT_EQ(3U, manager_->GetNumActiveInputMethods());
545 EXPECT_EQ(1, observer.input_method_changed_count_);
546 EXPECT_EQ(ImeIdFromEngineId(ids[0]), manager_->GetCurrentInputMethod().id());
547 EXPECT_EQ("us", keyboard_->last_layout_);
549 manager_->SwitchToNextInputMethod();
550 EXPECT_EQ(2, observer.input_method_changed_count_);
551 EXPECT_EQ(ImeIdFromEngineId(ids[1]), manager_->GetCurrentInputMethod().id());
552 EXPECT_EQ("us(dvorak)", keyboard_->last_layout_);
554 ids.erase(ids.begin() + 1);
555 EXPECT_TRUE(manager_->ReplaceEnabledInputMethods(ids));
556 EXPECT_EQ(2U, manager_->GetNumActiveInputMethods());
557 EXPECT_EQ(3, observer.input_method_changed_count_);
558 EXPECT_EQ(ImeIdFromEngineId(ids[0]), // US Qwerty
559 manager_->GetCurrentInputMethod().id());
560 EXPECT_EQ("us", keyboard_->last_layout_);
561 manager_->RemoveObserver(&observer);
564 TEST_F(InputMethodManagerImplTest, TestEnableLayoutAndIme) {
565 // For http://crbug.com/19655#c11 - (10).
566 TestObserver observer;
567 manager_->AddObserver(&observer);
568 InitComponentExtension();
569 manager_->SetState(InputMethodManager::STATE_BROWSER_SCREEN);
570 std::vector<std::string> ids;
571 ids.push_back(ImeIdFromEngineId("xkb:us:dvorak:eng"));
572 ids.push_back(ImeIdFromEngineId(kNaclMozcUsId));
573 EXPECT_TRUE(manager_->ReplaceEnabledInputMethods(ids));
574 EXPECT_EQ(1, observer.input_method_changed_count_);
575 EXPECT_EQ(ImeIdFromEngineId(ids[0]), manager_->GetCurrentInputMethod().id());
576 EXPECT_EQ("us(dvorak)", keyboard_->last_layout_);
578 manager_->SwitchToNextInputMethod();
579 EXPECT_EQ(2, observer.input_method_changed_count_);
580 EXPECT_EQ(ImeIdFromEngineId(ids[1]), manager_->GetCurrentInputMethod().id());
581 EXPECT_EQ("us", keyboard_->last_layout_);
583 ids.erase(ids.begin() + 1);
584 EXPECT_TRUE(manager_->ReplaceEnabledInputMethods(ids));
585 EXPECT_EQ(1U, manager_->GetNumActiveInputMethods());
586 EXPECT_EQ(ImeIdFromEngineId(ids[0]), manager_->GetCurrentInputMethod().id());
587 EXPECT_EQ("us(dvorak)", keyboard_->last_layout_);
590 TEST_F(InputMethodManagerImplTest, TestEnableLayoutAndIme2) {
591 // For http://crbug.com/19655#c11 - (11).
592 TestObserver observer;
593 manager_->AddObserver(&observer);
594 InitComponentExtension();
595 manager_->SetState(InputMethodManager::STATE_BROWSER_SCREEN);
596 std::vector<std::string> ids;
597 ids.push_back(ImeIdFromEngineId("xkb:us:dvorak:eng"));
598 ids.push_back(ImeIdFromEngineId(kNaclMozcUsId));
599 EXPECT_TRUE(manager_->ReplaceEnabledInputMethods(ids));
600 EXPECT_EQ(1, observer.input_method_changed_count_);
601 EXPECT_EQ(ImeIdFromEngineId(ids[0]), manager_->GetCurrentInputMethod().id());
602 EXPECT_EQ("us(dvorak)", keyboard_->last_layout_);
605 ids.erase(ids.begin());
606 EXPECT_TRUE(manager_->ReplaceEnabledInputMethods(ids));
607 EXPECT_EQ(1U, manager_->GetNumActiveInputMethods());
608 EXPECT_EQ(ImeIdFromEngineId(ids[0]), // Mozc
609 manager_->GetCurrentInputMethod().id());
610 EXPECT_EQ("us", keyboard_->last_layout_);
611 manager_->RemoveObserver(&observer);
614 TEST_F(InputMethodManagerImplTest, TestEnableImes) {
615 TestObserver observer;
616 manager_->AddObserver(&observer);
617 InitComponentExtension();
618 manager_->SetState(InputMethodManager::STATE_BROWSER_SCREEN);
619 std::vector<std::string> ids;
620 ids.push_back(ImeIdFromEngineId(kExt2Engine1Id));
621 ids.push_back("mozc-dv");
622 EXPECT_TRUE(manager_->ReplaceEnabledInputMethods(ids));
623 EXPECT_EQ(1, observer.input_method_changed_count_);
624 EXPECT_EQ(ImeIdFromEngineId(ids[0]), manager_->GetCurrentInputMethod().id());
625 EXPECT_EQ("us", keyboard_->last_layout_);
626 manager_->RemoveObserver(&observer);
629 TEST_F(InputMethodManagerImplTest, TestEnableUnknownIds) {
630 TestObserver observer;
631 manager_->AddObserver(&observer);
632 manager_->SetState(InputMethodManager::STATE_BROWSER_SCREEN);
633 std::vector<std::string> ids;
634 ids.push_back("xkb:tl::tlh"); // Klingon, which is not supported.
635 ids.push_back("unknown-super-cool-ime");
636 EXPECT_FALSE(manager_->ReplaceEnabledInputMethods(ids));
638 // TODO(yusukes): Should we fall back to the hardware keyboard layout in this
640 EXPECT_EQ(0, observer.input_method_changed_count_);
642 manager_->RemoveObserver(&observer);
645 TEST_F(InputMethodManagerImplTest, TestEnableLayoutsThenLock) {
646 // For http://crbug.com/19655#c11 - (14).
647 TestObserver observer;
648 manager_->AddObserver(&observer);
649 InitComponentExtension();
650 manager_->SetState(InputMethodManager::STATE_BROWSER_SCREEN);
651 std::vector<std::string> ids;
652 ids.push_back(ImeIdFromEngineId("xkb:us::eng"));
653 ids.push_back(ImeIdFromEngineId("xkb:us:dvorak:eng"));
654 EXPECT_TRUE(manager_->ReplaceEnabledInputMethods(ids));
655 EXPECT_EQ(2U, manager_->GetNumActiveInputMethods());
656 EXPECT_EQ(1, observer.input_method_changed_count_);
657 EXPECT_EQ(ImeIdFromEngineId(ids[0]), manager_->GetCurrentInputMethod().id());
658 EXPECT_EQ("us", keyboard_->last_layout_);
661 manager_->SwitchToNextInputMethod();
662 EXPECT_EQ(2, observer.input_method_changed_count_);
663 EXPECT_EQ(ImeIdFromEngineId(ids[1]), manager_->GetCurrentInputMethod().id());
664 EXPECT_EQ("us(dvorak)", keyboard_->last_layout_);
667 manager_->SetState(InputMethodManager::STATE_LOCK_SCREEN);
668 EXPECT_EQ(2U, manager_->GetNumActiveInputMethods());
669 EXPECT_EQ(ImeIdFromEngineId(ids[1]), // still Dvorak
670 manager_->GetCurrentInputMethod().id());
671 EXPECT_EQ("us(dvorak)", keyboard_->last_layout_);
672 // Switch back to Qwerty.
673 manager_->SwitchToNextInputMethod();
674 EXPECT_EQ(ImeIdFromEngineId(ids[0]), manager_->GetCurrentInputMethod().id());
675 EXPECT_EQ("us", keyboard_->last_layout_);
677 // Unlock screen. The original state, Dvorak, is restored.
678 manager_->SetState(InputMethodManager::STATE_BROWSER_SCREEN);
679 EXPECT_EQ(2U, manager_->GetNumActiveInputMethods());
680 EXPECT_EQ(ImeIdFromEngineId(ids[1]), manager_->GetCurrentInputMethod().id());
681 EXPECT_EQ("us(dvorak)", keyboard_->last_layout_);
683 manager_->RemoveObserver(&observer);
686 TEST_F(InputMethodManagerImplTest, SwitchInputMethodTest) {
687 // For http://crbug.com/19655#c11 - (15).
688 TestObserver observer;
689 manager_->AddObserver(&observer);
690 InitComponentExtension();
691 manager_->SetState(InputMethodManager::STATE_BROWSER_SCREEN);
692 std::vector<std::string> ids;
693 ids.push_back(ImeIdFromEngineId("xkb:us:dvorak:eng"));
694 ids.push_back(ImeIdFromEngineId(kExt2Engine2Id));
695 ids.push_back(ImeIdFromEngineId(kExt2Engine1Id));
696 EXPECT_TRUE(manager_->ReplaceEnabledInputMethods(ids));
697 EXPECT_EQ(3U, manager_->GetNumActiveInputMethods());
698 EXPECT_EQ(1, observer.input_method_changed_count_);
699 EXPECT_EQ(ImeIdFromEngineId(ids[0]), manager_->GetCurrentInputMethod().id());
700 EXPECT_EQ("us(dvorak)", keyboard_->last_layout_);
703 manager_->SwitchToNextInputMethod();
704 EXPECT_EQ(2, observer.input_method_changed_count_);
705 EXPECT_EQ(ImeIdFromEngineId(ids[1]), manager_->GetCurrentInputMethod().id());
706 EXPECT_EQ("us(dvorak)", keyboard_->last_layout_);
709 manager_->SetState(InputMethodManager::STATE_LOCK_SCREEN);
710 EXPECT_EQ(2U, manager_->GetNumActiveInputMethods()); // Qwerty+Dvorak.
711 EXPECT_EQ(ImeIdFromEngineId("xkb:us:dvorak:eng"),
712 manager_->GetCurrentInputMethod().id());
713 EXPECT_EQ("us(dvorak)", keyboard_->last_layout_);
714 manager_->SwitchToNextInputMethod();
715 EXPECT_EQ(ImeIdFromEngineId("xkb:us::eng"), // The hardware keyboard layout.
716 manager_->GetCurrentInputMethod().id());
717 EXPECT_EQ("us", keyboard_->last_layout_);
719 // Unlock screen. The original state, pinyin-dv, is restored.
720 manager_->SetState(InputMethodManager::STATE_BROWSER_SCREEN);
721 EXPECT_EQ(3U, manager_->GetNumActiveInputMethods()); // Dvorak and 2 IMEs.
722 EXPECT_EQ(ImeIdFromEngineId(ids[1]), manager_->GetCurrentInputMethod().id());
723 EXPECT_EQ("us(dvorak)", keyboard_->last_layout_);
725 manager_->RemoveObserver(&observer);
728 TEST_F(InputMethodManagerImplTest, TestXkbSetting) {
729 // For http://crbug.com/19655#c11 - (8), step 7-11.
730 InitComponentExtension();
731 manager_->SetState(InputMethodManager::STATE_BROWSER_SCREEN);
732 std::vector<std::string> ids;
733 ids.push_back(ImeIdFromEngineId("xkb:us:dvorak:eng"));
734 ids.push_back(ImeIdFromEngineId("xkb:us:colemak:eng"));
735 ids.push_back(ImeIdFromEngineId(kNaclMozcJpId));
736 ids.push_back(ImeIdFromEngineId(kNaclMozcUsId));
737 EXPECT_TRUE(manager_->ReplaceEnabledInputMethods(ids));
738 EXPECT_EQ(4U, manager_->GetNumActiveInputMethods());
739 EXPECT_EQ(1, keyboard_->set_current_keyboard_layout_by_name_count_);
740 // See input_methods.txt for an expected XKB layout name.
741 EXPECT_EQ("us(dvorak)", keyboard_->last_layout_);
742 manager_->SwitchToNextInputMethod();
743 EXPECT_EQ(2, keyboard_->set_current_keyboard_layout_by_name_count_);
744 EXPECT_EQ("us(colemak)", keyboard_->last_layout_);
745 manager_->SwitchToNextInputMethod();
746 EXPECT_EQ(3, keyboard_->set_current_keyboard_layout_by_name_count_);
747 EXPECT_EQ("jp", keyboard_->last_layout_);
748 manager_->SwitchToNextInputMethod();
749 EXPECT_EQ(4, keyboard_->set_current_keyboard_layout_by_name_count_);
750 EXPECT_EQ("us", keyboard_->last_layout_);
751 manager_->SwitchToNextInputMethod();
752 EXPECT_EQ(5, keyboard_->set_current_keyboard_layout_by_name_count_);
753 EXPECT_EQ("us(dvorak)", keyboard_->last_layout_);
755 ids.erase(ids.begin());
756 EXPECT_TRUE(manager_->ReplaceEnabledInputMethods(ids));
757 EXPECT_EQ(3U, manager_->GetNumActiveInputMethods());
758 EXPECT_EQ(6, keyboard_->set_current_keyboard_layout_by_name_count_);
759 EXPECT_EQ("us(colemak)", keyboard_->last_layout_);
762 TEST_F(InputMethodManagerImplTest, TestActivateInputMethodMenuItem) {
763 const std::string kKey = "key";
764 ash::ime::InputMethodMenuItemList menu_list;
765 menu_list.push_back(ash::ime::InputMethodMenuItem(
766 kKey, "label", false, false));
767 menu_manager_->SetCurrentInputMethodMenuItemList(menu_list);
769 manager_->ActivateInputMethodMenuItem(kKey);
770 EXPECT_EQ(kKey, mock_engine_handler_->last_activated_property());
772 // Key2 is not registered, so activated property should not be changed.
773 manager_->ActivateInputMethodMenuItem("key2");
774 EXPECT_EQ(kKey, mock_engine_handler_->last_activated_property());
777 TEST_F(InputMethodManagerImplTest, TestGetCurrentInputMethodProperties) {
778 InitComponentExtension();
779 EXPECT_TRUE(menu_manager_->GetCurrentInputMethodMenuItemList().empty());
781 manager_->SetState(InputMethodManager::STATE_BROWSER_SCREEN);
782 std::vector<std::string> ids;
783 ids.push_back(ImeIdFromEngineId("xkb:us::eng"));
784 ids.push_back(ImeIdFromEngineId(kNaclMozcUsId));
785 EXPECT_TRUE(manager_->ReplaceEnabledInputMethods(ids));
786 EXPECT_EQ(2U, manager_->GetNumActiveInputMethods());
787 EXPECT_TRUE(menu_manager_->GetCurrentInputMethodMenuItemList().empty());
788 manager_->ChangeInputMethod(ImeIdFromEngineId(kNaclMozcUsId));
790 ash::ime::InputMethodMenuItemList current_property_list;
791 current_property_list.push_back(ash::ime::InputMethodMenuItem(
792 "key", "label", false, false));
793 menu_manager_->SetCurrentInputMethodMenuItemList(current_property_list);
795 ASSERT_EQ(1U, menu_manager_->GetCurrentInputMethodMenuItemList().size());
797 menu_manager_->GetCurrentInputMethodMenuItemList().at(0).key);
799 manager_->ChangeInputMethod("xkb:us::eng");
800 EXPECT_TRUE(menu_manager_->GetCurrentInputMethodMenuItemList().empty());
803 TEST_F(InputMethodManagerImplTest, TestGetCurrentInputMethodPropertiesTwoImes) {
804 InitComponentExtension();
805 EXPECT_TRUE(menu_manager_->GetCurrentInputMethodMenuItemList().empty());
807 manager_->SetState(InputMethodManager::STATE_BROWSER_SCREEN);
808 std::vector<std::string> ids;
809 ids.push_back(ImeIdFromEngineId(kNaclMozcUsId)); // Japanese
810 ids.push_back(ImeIdFromEngineId(kExt2Engine1Id)); // T-Chinese
811 EXPECT_TRUE(manager_->ReplaceEnabledInputMethods(ids));
812 EXPECT_EQ(2U, manager_->GetNumActiveInputMethods());
813 EXPECT_TRUE(menu_manager_->GetCurrentInputMethodMenuItemList().empty());
815 ash::ime::InputMethodMenuItemList current_property_list;
816 current_property_list.push_back(ash::ime::InputMethodMenuItem("key-mozc",
820 menu_manager_->SetCurrentInputMethodMenuItemList(current_property_list);
822 ASSERT_EQ(1U, menu_manager_->GetCurrentInputMethodMenuItemList().size());
823 EXPECT_EQ("key-mozc",
824 menu_manager_->GetCurrentInputMethodMenuItemList().at(0).key);
826 manager_->ChangeInputMethod(ImeIdFromEngineId(kExt2Engine1Id));
827 // Since the IME is changed, the property for mozc Japanese should be hidden.
828 EXPECT_TRUE(menu_manager_->GetCurrentInputMethodMenuItemList().empty());
830 // Asynchronous property update signal from mozc-chewing.
831 current_property_list.clear();
832 current_property_list.push_back(ash::ime::InputMethodMenuItem(
833 "key-chewing", "label", false, false));
834 menu_manager_->SetCurrentInputMethodMenuItemList(current_property_list);
835 ASSERT_EQ(1U, menu_manager_->GetCurrentInputMethodMenuItemList().size());
836 EXPECT_EQ("key-chewing",
837 menu_manager_->GetCurrentInputMethodMenuItemList().at(0).key);
840 TEST_F(InputMethodManagerImplTest, TestNextInputMethod) {
841 TestObserver observer;
842 manager_->AddObserver(&observer);
843 InitComponentExtension();
844 std::vector<std::string> keyboard_layouts;
845 keyboard_layouts.push_back(ImeIdFromEngineId("xkb:us::eng"));
846 // For http://crbug.com/19655#c11 - (1)
847 manager_->EnableLoginLayouts("en-US", keyboard_layouts);
848 EXPECT_EQ(5U, manager_->GetNumActiveInputMethods());
849 EXPECT_EQ(ImeIdFromEngineId("xkb:us::eng"),
850 manager_->GetCurrentInputMethod().id());
851 EXPECT_EQ("us", keyboard_->last_layout_);
852 manager_->SwitchToNextInputMethod();
853 EXPECT_TRUE(observer.last_show_message_);
854 EXPECT_EQ(ImeIdFromEngineId("xkb:us:intl:eng"),
855 manager_->GetCurrentInputMethod().id());
856 EXPECT_EQ("us(intl)", keyboard_->last_layout_);
857 manager_->SwitchToNextInputMethod();
858 EXPECT_TRUE(observer.last_show_message_);
859 EXPECT_EQ(ImeIdFromEngineId("xkb:us:altgr-intl:eng"),
860 manager_->GetCurrentInputMethod().id());
861 EXPECT_EQ("us(altgr-intl)", keyboard_->last_layout_);
862 manager_->SwitchToNextInputMethod();
863 EXPECT_TRUE(observer.last_show_message_);
864 EXPECT_EQ(ImeIdFromEngineId("xkb:us:dvorak:eng"),
865 manager_->GetCurrentInputMethod().id());
866 EXPECT_EQ("us(dvorak)", keyboard_->last_layout_);
867 manager_->SwitchToNextInputMethod();
868 EXPECT_TRUE(observer.last_show_message_);
869 EXPECT_EQ(ImeIdFromEngineId("xkb:us:colemak:eng"),
870 manager_->GetCurrentInputMethod().id());
871 EXPECT_EQ("us(colemak)", keyboard_->last_layout_);
872 manager_->SwitchToNextInputMethod();
873 EXPECT_TRUE(observer.last_show_message_);
874 EXPECT_EQ(ImeIdFromEngineId("xkb:us::eng"),
875 manager_->GetCurrentInputMethod().id());
876 EXPECT_EQ("us", keyboard_->last_layout_);
878 manager_->RemoveObserver(&observer);
881 TEST_F(InputMethodManagerImplTest, TestPreviousInputMethod) {
882 TestObserver observer;
883 manager_->AddObserver(&observer);
884 InitComponentExtension();
886 ui::Accelerator keydown_accelerator(ui::VKEY_SPACE, ui::EF_CONTROL_DOWN);
887 keydown_accelerator.set_type(ui::ET_KEY_PRESSED);
888 ui::Accelerator keyup_accelerator(ui::VKEY_SPACE, ui::EF_CONTROL_DOWN);
889 keyup_accelerator.set_type(ui::ET_KEY_RELEASED);
891 std::vector<std::string> keyboard_layouts;
892 keyboard_layouts.push_back(ImeIdFromEngineId("xkb:us::eng"));
893 manager_->EnableLoginLayouts("en-US", keyboard_layouts);
894 EXPECT_EQ(5U, manager_->GetNumActiveInputMethods());
895 EXPECT_EQ(ImeIdFromEngineId("xkb:us::eng"),
896 manager_->GetCurrentInputMethod().id());
897 EXPECT_EQ("us", keyboard_->last_layout_);
898 EXPECT_TRUE(manager_->SwitchToNextInputMethod());
899 EXPECT_TRUE(observer.last_show_message_);
900 EXPECT_EQ(ImeIdFromEngineId("xkb:us:intl:eng"),
901 manager_->GetCurrentInputMethod().id());
902 EXPECT_EQ("us(intl)", keyboard_->last_layout_);
903 EXPECT_TRUE(manager_->SwitchToPreviousInputMethod(keydown_accelerator));
904 EXPECT_TRUE(manager_->SwitchToPreviousInputMethod(keyup_accelerator));
905 EXPECT_TRUE(observer.last_show_message_);
906 EXPECT_EQ(ImeIdFromEngineId("xkb:us::eng"),
907 manager_->GetCurrentInputMethod().id());
908 EXPECT_EQ("us", keyboard_->last_layout_);
909 EXPECT_TRUE(manager_->SwitchToPreviousInputMethod(keydown_accelerator));
910 EXPECT_TRUE(manager_->SwitchToPreviousInputMethod(keyup_accelerator));
911 EXPECT_TRUE(observer.last_show_message_);
912 EXPECT_EQ(ImeIdFromEngineId("xkb:us:intl:eng"),
913 manager_->GetCurrentInputMethod().id());
914 EXPECT_EQ("us(intl)", keyboard_->last_layout_);
915 EXPECT_TRUE(manager_->SwitchToPreviousInputMethod(keydown_accelerator));
916 EXPECT_TRUE(manager_->SwitchToPreviousInputMethod(keyup_accelerator));
917 EXPECT_TRUE(observer.last_show_message_);
918 EXPECT_EQ(ImeIdFromEngineId("xkb:us::eng"),
919 manager_->GetCurrentInputMethod().id());
920 EXPECT_EQ("us", keyboard_->last_layout_);
921 EXPECT_TRUE(manager_->SwitchToNextInputMethod());
922 EXPECT_TRUE(observer.last_show_message_);
923 EXPECT_EQ(ImeIdFromEngineId("xkb:us:intl:eng"),
924 manager_->GetCurrentInputMethod().id());
925 EXPECT_EQ("us(intl)", keyboard_->last_layout_);
926 EXPECT_TRUE(manager_->SwitchToNextInputMethod());
927 EXPECT_TRUE(observer.last_show_message_);
928 EXPECT_EQ(ImeIdFromEngineId("xkb:us:altgr-intl:eng"),
929 manager_->GetCurrentInputMethod().id());
930 EXPECT_EQ("us(altgr-intl)", keyboard_->last_layout_);
931 EXPECT_TRUE(manager_->SwitchToPreviousInputMethod(keydown_accelerator));
932 EXPECT_TRUE(manager_->SwitchToPreviousInputMethod(keyup_accelerator));
933 EXPECT_TRUE(observer.last_show_message_);
934 EXPECT_EQ(ImeIdFromEngineId("xkb:us:intl:eng"),
935 manager_->GetCurrentInputMethod().id());
936 EXPECT_EQ("us(intl)", keyboard_->last_layout_);
937 EXPECT_TRUE(manager_->SwitchToPreviousInputMethod(keydown_accelerator));
938 EXPECT_TRUE(manager_->SwitchToPreviousInputMethod(keyup_accelerator));
939 EXPECT_TRUE(observer.last_show_message_);
940 EXPECT_EQ(ImeIdFromEngineId("xkb:us:altgr-intl:eng"),
941 manager_->GetCurrentInputMethod().id());
942 EXPECT_EQ("us(altgr-intl)", keyboard_->last_layout_);
944 manager_->RemoveObserver(&observer);
947 TEST_F(InputMethodManagerImplTest,
948 TestSwitchToPreviousInputMethodForOneActiveInputMethod) {
949 TestObserver observer;
950 manager_->AddObserver(&observer);
951 InitComponentExtension();
953 ui::Accelerator keydown_accelerator(ui::VKEY_SPACE, ui::EF_CONTROL_DOWN);
954 keydown_accelerator.set_type(ui::ET_KEY_PRESSED);
955 ui::Accelerator keyup_accelerator(ui::VKEY_SPACE, ui::EF_CONTROL_DOWN);
956 keyup_accelerator.set_type(ui::ET_KEY_RELEASED);
958 std::vector<std::string> ids;
959 ids.push_back(ImeIdFromEngineId("xkb:us:dvorak:eng"));
960 EXPECT_TRUE(manager_->ReplaceEnabledInputMethods(ids));
961 EXPECT_EQ(1U, manager_->GetNumActiveInputMethods());
963 // Ctrl+Space accelerator should not be consumed if there is only one active
965 EXPECT_FALSE(manager_->SwitchToPreviousInputMethod(keydown_accelerator));
966 EXPECT_FALSE(manager_->SwitchToPreviousInputMethod(keyup_accelerator));
968 manager_->RemoveObserver(&observer);
971 TEST_F(InputMethodManagerImplTest, TestSwitchInputMethodWithUsLayouts) {
972 std::string expect_id = ImeIdFromEngineId("xkb:us::eng");
973 TestObserver observer;
974 manager_->AddObserver(&observer);
975 InitComponentExtension();
976 std::vector<std::string> keyboard_layouts;
977 keyboard_layouts.push_back(ImeIdFromEngineId("xkb:us::eng"));
978 manager_->EnableLoginLayouts("en-US", keyboard_layouts);
979 EXPECT_EQ(5U, manager_->GetNumActiveInputMethods());
980 EXPECT_EQ(expect_id, manager_->GetCurrentInputMethod().id());
981 EXPECT_EQ("us", keyboard_->last_layout_);
983 // Henkan, Muhenkan, ZenkakuHankaku should be ignored when no Japanese IMEs
984 // and keyboards are enabled.
985 EXPECT_FALSE(manager_->SwitchInputMethod(
986 ui::Accelerator(ui::VKEY_CONVERT, ui::EF_NONE)));
987 EXPECT_FALSE(observer.last_show_message_);
988 EXPECT_EQ(expect_id, manager_->GetCurrentInputMethod().id());
989 EXPECT_EQ("us", keyboard_->last_layout_);
990 EXPECT_FALSE(manager_->SwitchInputMethod(
991 ui::Accelerator(ui::VKEY_NONCONVERT, ui::EF_NONE)));
992 EXPECT_EQ(expect_id, manager_->GetCurrentInputMethod().id());
993 EXPECT_EQ("us", keyboard_->last_layout_);
994 EXPECT_FALSE(manager_->SwitchInputMethod(
995 ui::Accelerator(ui::VKEY_DBE_SBCSCHAR, ui::EF_NONE)));
996 EXPECT_EQ(expect_id, manager_->GetCurrentInputMethod().id());
997 EXPECT_EQ("us", keyboard_->last_layout_);
998 EXPECT_FALSE(manager_->SwitchInputMethod(
999 ui::Accelerator(ui::VKEY_DBE_DBCSCHAR, ui::EF_NONE)));
1000 EXPECT_EQ(expect_id, manager_->GetCurrentInputMethod().id());
1001 EXPECT_EQ("us", keyboard_->last_layout_);
1003 manager_->RemoveObserver(&observer);
1006 TEST_F(InputMethodManagerImplTest, TestSwitchInputMethodWithJpLayout) {
1007 // Enable "xkb:jp::jpn" and press Muhenkan/ZenkakuHankaku.
1008 InitComponentExtension();
1010 ui::Accelerator keydown_accelerator(ui::VKEY_SPACE, ui::EF_CONTROL_DOWN);
1011 keydown_accelerator.set_type(ui::ET_KEY_PRESSED);
1012 ui::Accelerator keyup_accelerator(ui::VKEY_SPACE, ui::EF_CONTROL_DOWN);
1013 keyup_accelerator.set_type(ui::ET_KEY_RELEASED);
1015 std::vector<std::string> keyboard_layouts;
1016 keyboard_layouts.push_back(ImeIdFromEngineId("xkb:us::eng"));
1017 manager_->EnableLoginLayouts("ja", keyboard_layouts);
1018 EXPECT_EQ(2U, manager_->GetNumActiveInputMethods());
1019 EXPECT_EQ(ImeIdFromEngineId("xkb:us::eng"),
1020 manager_->GetCurrentInputMethod().id());
1021 EXPECT_EQ("us", keyboard_->last_layout_);
1022 EXPECT_TRUE(manager_->SwitchInputMethod(
1023 ui::Accelerator(ui::VKEY_NONCONVERT, ui::EF_NONE)));
1024 EXPECT_EQ(ImeIdFromEngineId("xkb:jp::jpn"),
1025 manager_->GetCurrentInputMethod().id());
1026 EXPECT_EQ("jp", keyboard_->last_layout_);
1027 EXPECT_TRUE(manager_->SwitchToPreviousInputMethod(keydown_accelerator));
1028 EXPECT_TRUE(manager_->SwitchToPreviousInputMethod(keyup_accelerator));
1029 EXPECT_EQ(ImeIdFromEngineId("xkb:us::eng"),
1030 manager_->GetCurrentInputMethod().id());
1031 EXPECT_EQ("us", keyboard_->last_layout_);
1032 EXPECT_TRUE(manager_->SwitchInputMethod(
1033 ui::Accelerator(ui::VKEY_DBE_SBCSCHAR, ui::EF_NONE)));
1034 EXPECT_EQ(ImeIdFromEngineId("xkb:jp::jpn"),
1035 manager_->GetCurrentInputMethod().id());
1036 EXPECT_EQ("jp", keyboard_->last_layout_);
1037 EXPECT_TRUE(manager_->SwitchToPreviousInputMethod(keydown_accelerator));
1038 EXPECT_TRUE(manager_->SwitchToPreviousInputMethod(keyup_accelerator));
1039 EXPECT_EQ(ImeIdFromEngineId("xkb:us::eng"),
1040 manager_->GetCurrentInputMethod().id());
1041 EXPECT_EQ("us", keyboard_->last_layout_);
1042 EXPECT_TRUE(manager_->SwitchInputMethod(
1043 ui::Accelerator(ui::VKEY_DBE_DBCSCHAR, ui::EF_NONE)));
1044 EXPECT_EQ(ImeIdFromEngineId("xkb:jp::jpn"),
1045 manager_->GetCurrentInputMethod().id());
1046 EXPECT_EQ("jp", keyboard_->last_layout_);
1049 TEST_F(InputMethodManagerImplTest, TestSwitchInputMethodWithJpIme) {
1050 InitComponentExtension();
1051 manager_->SetState(InputMethodManager::STATE_BROWSER_SCREEN);
1052 std::vector<std::string> ids;
1053 ids.push_back(ImeIdFromEngineId("xkb:jp::jpn"));
1054 ids.push_back(ImeIdFromEngineId(kNaclMozcJpId));
1055 EXPECT_TRUE(manager_->ReplaceEnabledInputMethods(ids));
1056 EXPECT_EQ(ImeIdFromEngineId("xkb:jp::jpn"),
1057 manager_->GetCurrentInputMethod().id());
1058 EXPECT_EQ("jp", keyboard_->last_layout_);
1059 EXPECT_TRUE(manager_->SwitchInputMethod(
1060 ui::Accelerator(ui::VKEY_DBE_DBCSCHAR, ui::EF_NONE)));
1061 EXPECT_EQ(ImeIdFromEngineId(kNaclMozcJpId),
1062 manager_->GetCurrentInputMethod().id());
1063 EXPECT_EQ("jp", keyboard_->last_layout_);
1064 EXPECT_TRUE(manager_->SwitchInputMethod(
1065 ui::Accelerator(ui::VKEY_DBE_DBCSCHAR, ui::EF_NONE)));
1066 EXPECT_EQ(ImeIdFromEngineId("xkb:jp::jpn"),
1067 manager_->GetCurrentInputMethod().id());
1068 EXPECT_EQ("jp", keyboard_->last_layout_);
1069 EXPECT_TRUE(manager_->SwitchInputMethod(
1070 ui::Accelerator(ui::VKEY_CONVERT, ui::EF_NONE)));
1071 EXPECT_EQ(ImeIdFromEngineId(kNaclMozcJpId),
1072 manager_->GetCurrentInputMethod().id());
1073 EXPECT_EQ("jp", keyboard_->last_layout_);
1074 EXPECT_TRUE(manager_->SwitchInputMethod(
1075 ui::Accelerator(ui::VKEY_CONVERT, ui::EF_NONE)));
1076 EXPECT_EQ(ImeIdFromEngineId(kNaclMozcJpId),
1077 manager_->GetCurrentInputMethod().id());
1078 EXPECT_EQ("jp", keyboard_->last_layout_);
1079 EXPECT_TRUE(manager_->SwitchInputMethod(
1080 ui::Accelerator(ui::VKEY_NONCONVERT, ui::EF_NONE)));
1081 EXPECT_EQ(ImeIdFromEngineId("xkb:jp::jpn"),
1082 manager_->GetCurrentInputMethod().id());
1083 EXPECT_EQ("jp", keyboard_->last_layout_);
1084 EXPECT_TRUE(manager_->SwitchInputMethod(
1085 ui::Accelerator(ui::VKEY_NONCONVERT, ui::EF_NONE)));
1086 EXPECT_EQ(ImeIdFromEngineId("xkb:jp::jpn"),
1087 manager_->GetCurrentInputMethod().id());
1088 EXPECT_EQ("jp", keyboard_->last_layout_);
1091 ids.push_back(ImeIdFromEngineId("xkb:us:dvorak:eng"));
1092 EXPECT_TRUE(manager_->ReplaceEnabledInputMethods(ids));
1093 EXPECT_EQ(ImeIdFromEngineId("xkb:jp::jpn"),
1094 manager_->GetCurrentInputMethod().id());
1095 EXPECT_EQ("jp", keyboard_->last_layout_);
1096 EXPECT_TRUE(manager_->SwitchInputMethod(
1097 ui::Accelerator(ui::VKEY_DBE_SBCSCHAR, ui::EF_NONE)));
1098 EXPECT_EQ(ImeIdFromEngineId(kNaclMozcJpId),
1099 manager_->GetCurrentInputMethod().id());
1100 EXPECT_EQ("jp", keyboard_->last_layout_);
1101 EXPECT_TRUE(manager_->SwitchInputMethod(
1102 ui::Accelerator(ui::VKEY_DBE_SBCSCHAR, ui::EF_NONE)));
1103 EXPECT_EQ(ImeIdFromEngineId("xkb:jp::jpn"),
1104 manager_->GetCurrentInputMethod().id());
1105 EXPECT_EQ("jp", keyboard_->last_layout_);
1108 TEST_F(InputMethodManagerImplTest, TestAddRemoveExtensionInputMethods) {
1109 TestObserver observer;
1110 manager_->AddObserver(&observer);
1111 InitComponentExtension();
1112 manager_->SetState(InputMethodManager::STATE_BROWSER_SCREEN);
1113 std::vector<std::string> ids;
1114 ids.push_back(ImeIdFromEngineId("xkb:us:dvorak:eng"));
1115 EXPECT_TRUE(manager_->ReplaceEnabledInputMethods(ids));
1116 EXPECT_EQ(1U, manager_->GetNumActiveInputMethods());
1117 EXPECT_EQ(1, observer.input_method_changed_count_);
1118 EXPECT_EQ(ImeIdFromEngineId(ids[0]), manager_->GetCurrentInputMethod().id());
1119 EXPECT_EQ("us(dvorak)", keyboard_->last_layout_);
1121 // Add two Extension IMEs.
1122 std::vector<std::string> layouts;
1123 layouts.push_back("us");
1124 std::vector<std::string> languages;
1125 languages.push_back("en-US");
1127 const std::string ext1_id =
1128 extension_ime_util::GetInputMethodID(kExtensionId1, "engine_id");
1129 const InputMethodDescriptor descriptor1(ext1_id,
1130 "deadbeef input method",
1134 false, // is_login_keyboard
1137 MockInputMethodEngine engine;
1138 InputMethodDescriptors descriptors;
1139 descriptors.push_back(descriptor1);
1140 manager_->AddInputMethodExtension(kExtensionId1, descriptors, &engine);
1142 // Extension IMEs are not enabled by default.
1143 EXPECT_EQ(1U, manager_->GetNumActiveInputMethods());
1145 std::vector<std::string> extension_ime_ids;
1146 extension_ime_ids.push_back(ext1_id);
1147 manager_->SetEnabledExtensionImes(&extension_ime_ids);
1148 EXPECT_EQ(2U, manager_->GetNumActiveInputMethods());
1151 scoped_ptr<InputMethodDescriptors> methods(
1152 manager_->GetActiveInputMethods());
1153 ASSERT_EQ(2U, methods->size());
1154 // Ext IMEs should be at the end of the list.
1155 EXPECT_EQ(ext1_id, methods->at(1).id());
1158 const std::string ext2_id =
1159 extension_ime_util::GetInputMethodID(kExtensionId2, "engine_id");
1160 const InputMethodDescriptor descriptor2(ext2_id,
1161 "cafebabe input method",
1165 false, // is_login_keyboard
1168 descriptors.clear();
1169 descriptors.push_back(descriptor2);
1170 MockInputMethodEngine engine2;
1171 manager_->AddInputMethodExtension(kExtensionId2, descriptors, &engine2);
1172 EXPECT_EQ(2U, manager_->GetNumActiveInputMethods());
1174 extension_ime_ids.push_back(ext2_id);
1175 manager_->SetEnabledExtensionImes(&extension_ime_ids);
1176 EXPECT_EQ(3U, manager_->GetNumActiveInputMethods());
1178 scoped_ptr<InputMethodDescriptors> methods(
1179 manager_->GetActiveInputMethods());
1180 ASSERT_EQ(3U, methods->size());
1181 // Ext IMEs should be at the end of the list.
1182 EXPECT_EQ(ext1_id, methods->at(1).id());
1183 EXPECT_EQ(ext2_id, methods->at(2).id());
1187 manager_->RemoveInputMethodExtension(kExtensionId1);
1188 EXPECT_EQ(2U, manager_->GetNumActiveInputMethods());
1189 manager_->RemoveInputMethodExtension(kExtensionId2);
1190 EXPECT_EQ(1U, manager_->GetNumActiveInputMethods());
1193 TEST_F(InputMethodManagerImplTest, TestAddExtensionInputThenLockScreen) {
1194 TestObserver observer;
1195 InitComponentExtension();
1196 manager_->AddObserver(&observer);
1197 manager_->SetState(InputMethodManager::STATE_BROWSER_SCREEN);
1198 std::vector<std::string> ids;
1199 ids.push_back(ImeIdFromEngineId("xkb:us::eng"));
1200 EXPECT_TRUE(manager_->ReplaceEnabledInputMethods(ids));
1201 EXPECT_EQ(1U, manager_->GetNumActiveInputMethods());
1202 EXPECT_EQ(1, observer.input_method_changed_count_);
1203 EXPECT_EQ(ImeIdFromEngineId(ids[0]), manager_->GetCurrentInputMethod().id());
1204 EXPECT_EQ("us", keyboard_->last_layout_);
1206 // Add an Extension IME.
1207 std::vector<std::string> layouts;
1208 layouts.push_back("us(dvorak)");
1209 std::vector<std::string> languages;
1210 languages.push_back("en-US");
1212 const std::string ext_id =
1213 extension_ime_util::GetInputMethodID(kExtensionId1, "engine_id");
1214 const InputMethodDescriptor descriptor(ext_id,
1215 "deadbeef input method",
1219 false, // is_login_keyboard
1222 MockInputMethodEngine engine;
1223 InputMethodDescriptors descriptors;
1224 descriptors.push_back(descriptor);
1225 manager_->AddInputMethodExtension(kExtensionId1, descriptors, &engine);
1227 // Extension IME is not enabled by default.
1228 EXPECT_EQ(1U, manager_->GetNumActiveInputMethods());
1229 EXPECT_EQ(1, observer.input_method_changed_count_);
1231 std::vector<std::string> extension_ime_ids;
1232 extension_ime_ids.push_back(ext_id);
1233 manager_->SetEnabledExtensionImes(&extension_ime_ids);
1234 EXPECT_EQ(2U, manager_->GetNumActiveInputMethods());
1236 // Switch to the IME.
1237 manager_->SwitchToNextInputMethod();
1238 EXPECT_EQ(3, observer.input_method_changed_count_);
1239 EXPECT_EQ(ext_id, manager_->GetCurrentInputMethod().id());
1240 EXPECT_EQ("us(dvorak)", keyboard_->last_layout_);
1242 // Lock the screen. This is for crosbug.com/27049.
1243 manager_->SetState(InputMethodManager::STATE_LOCK_SCREEN);
1244 EXPECT_EQ(1U, manager_->GetNumActiveInputMethods()); // Qwerty. No Ext. IME
1245 EXPECT_EQ(ImeIdFromEngineId("xkb:us::eng"),
1246 manager_->GetCurrentInputMethod().id());
1247 EXPECT_EQ("us", keyboard_->last_layout_);
1249 // Unlock the screen.
1250 manager_->SetState(InputMethodManager::STATE_BROWSER_SCREEN);
1251 EXPECT_EQ(2U, manager_->GetNumActiveInputMethods());
1252 EXPECT_EQ(ext_id, manager_->GetCurrentInputMethod().id());
1253 EXPECT_EQ("us(dvorak)", keyboard_->last_layout_);
1255 // This is for crosbug.com/27052.
1256 scoped_ptr<InputMethodDescriptors> methods(
1257 manager_->GetActiveInputMethods());
1258 ASSERT_EQ(2U, methods->size());
1259 // Ext. IMEs should be at the end of the list.
1260 EXPECT_EQ(ext_id, methods->at(1).id());
1262 manager_->RemoveObserver(&observer);
1265 TEST_F(InputMethodManagerImplTest,
1266 ChangeInputMethod_ComponenteExtensionOneIME) {
1267 InitComponentExtension();
1268 manager_->SetState(InputMethodManager::STATE_BROWSER_SCREEN);
1269 const std::string ext_id = extension_ime_util::GetComponentInputMethodID(
1271 ime_list_[1].engines[0].engine_id);
1272 std::vector<std::string> ids;
1273 ids.push_back(ext_id);
1274 EXPECT_TRUE(manager_->ReplaceEnabledInputMethods(ids));
1275 EXPECT_EQ(1U, manager_->GetNumActiveInputMethods());
1276 EXPECT_EQ(ext_id, manager_->GetCurrentInputMethod().id());
1279 TEST_F(InputMethodManagerImplTest,
1280 ChangeInputMethod_ComponenteExtensionTwoIME) {
1281 InitComponentExtension();
1282 manager_->SetState(InputMethodManager::STATE_BROWSER_SCREEN);
1283 const std::string ext_id1 = extension_ime_util::GetComponentInputMethodID(
1285 ime_list_[1].engines[0].engine_id);
1286 const std::string ext_id2 = extension_ime_util::GetComponentInputMethodID(
1288 ime_list_[2].engines[0].engine_id);
1289 std::vector<std::string> ids;
1290 ids.push_back(ext_id1);
1291 ids.push_back(ext_id2);
1292 EXPECT_TRUE(manager_->ReplaceEnabledInputMethods(ids));
1293 EXPECT_EQ(2U, manager_->GetNumActiveInputMethods());
1294 EXPECT_EQ(ext_id1, manager_->GetCurrentInputMethod().id());
1295 manager_->ChangeInputMethod(ext_id2);
1296 EXPECT_EQ(ext_id2, manager_->GetCurrentInputMethod().id());
1299 TEST_F(InputMethodManagerImplTest, MigrateInputMethodTest) {
1300 std::vector<std::string> input_method_ids;
1301 input_method_ids.push_back("xkb:us::eng");
1302 input_method_ids.push_back("xkb:fr::fra");
1303 input_method_ids.push_back(ImeIdFromEngineId("xkb:us::eng"));
1304 input_method_ids.push_back("xkb:fr::fra");
1305 input_method_ids.push_back(ImeIdFromEngineId("xkb:us::eng"));
1306 input_method_ids.push_back("_comp_ime_asdf_pinyin");
1307 input_method_ids.push_back(ImeIdFromEngineId(kPinyinImeId));
1309 manager_->MigrateInputMethods(&input_method_ids);
1311 ASSERT_EQ(4U, input_method_ids.size());
1313 EXPECT_EQ(ImeIdFromEngineId("xkb:us::eng"), input_method_ids[0]);
1314 EXPECT_EQ(ImeIdFromEngineId("xkb:fr::fra"), input_method_ids[1]);
1315 EXPECT_EQ("_comp_ime_asdf_pinyin", input_method_ids[2]);
1316 EXPECT_EQ(ImeIdFromEngineId("zh-t-i0-pinyin"), input_method_ids[3]);
1319 } // namespace input_method
1320 } // namespace chromeos