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 "base/basictypes.h"
10 #include "base/bind.h"
11 #include "base/bind_helpers.h"
12 #include "base/compiler_specific.h"
13 #include "base/logging.h"
14 #include "base/memory/scoped_ptr.h"
15 #include "base/message_loop/message_loop.h"
16 #include "chrome/browser/chromeos/input_method/input_method_engine_interface.h"
17 #include "chrome/browser/chromeos/input_method/mock_candidate_window_controller.h"
18 #include "chrome/browser/chromeos/input_method/mock_input_method_engine.h"
19 #include "chromeos/ime/extension_ime_util.h"
20 #include "chromeos/ime/fake_input_method_delegate.h"
21 #include "chromeos/ime/fake_xkeyboard.h"
22 #include "chromeos/ime/mock_component_extension_ime_manager_delegate.h"
23 #include "testing/gtest/include/gtest/gtest.h"
24 #include "ui/base/accelerators/accelerator.h"
25 #include "ui/base/ime/chromeos/mock_ime_engine_handler.h"
26 #include "ui/events/keycodes/keyboard_codes.h"
30 namespace input_method {
33 const char kNaclMozcUsId[] =
34 "_comp_ime_fpfbhcjppmaeaijcidgiibchfbnhbeljnacl_mozc_us";
35 const char kNaclMozcJpId[] =
36 "_comp_ime_fpfbhcjppmaeaijcidgiibchfbnhbeljnacl_mozc_jp";
37 const char kExt2Engine1Id[] =
38 "_comp_ime_nmblnjkfdkabgdofidlkienfnnbjhnabext2_engine1_engine_id";
39 const char kExt2Engine2Id[] =
40 "_comp_ime_nmblnjkfdkabgdofidlkienfnnbjhnabext2_engine2_engine_id";
42 // Returns true if |descriptors| contain |target|.
43 bool Contain(const InputMethodDescriptors& descriptors,
44 const InputMethodDescriptor& target) {
45 for (size_t i = 0; i < descriptors.size(); ++i) {
46 if (descriptors[i].id() == target.id())
52 class InputMethodManagerImplTest : public testing::Test {
54 InputMethodManagerImplTest()
56 candidate_window_controller_(NULL),
59 virtual ~InputMethodManagerImplTest() {}
61 virtual void SetUp() OVERRIDE {
62 delegate_ = new FakeInputMethodDelegate();
63 manager_.reset(new InputMethodManagerImpl(
64 scoped_ptr<InputMethodDelegate>(delegate_)));
65 manager_->GetInputMethodUtil()->UpdateHardwareLayoutCache();
66 candidate_window_controller_ = new MockCandidateWindowController;
67 manager_->SetCandidateWindowControllerForTesting(
68 candidate_window_controller_);
69 xkeyboard_ = new FakeXKeyboard;
70 manager_->SetXKeyboardForTesting(xkeyboard_);
71 mock_engine_handler_.reset(new MockIMEEngineHandler());
72 IMEBridge::Initialize();
73 IMEBridge::Get()->SetCurrentEngineHandler(mock_engine_handler_.get());
77 ComponentExtensionIME ext1;
78 ext1.id = "fpfbhcjppmaeaijcidgiibchfbnhbelj";
79 ext1.description = "ext1_description";
80 ext1.path = base::FilePath("ext1_file_path");
82 ComponentExtensionEngine ext1_engine1;
83 ext1_engine1.engine_id = "nacl_mozc_us";
84 ext1_engine1.display_name = "ext1_engine_1_display_name";
85 ext1_engine1.language_codes.push_back("ja");
86 ext1_engine1.layouts.push_back("us");
87 ext1.engines.push_back(ext1_engine1);
89 ComponentExtensionEngine ext1_engine2;
90 ext1_engine2.engine_id = "nacl_mozc_jp";
91 ext1_engine2.display_name = "ext1_engine_1_display_name";
92 ext1_engine2.language_codes.push_back("ja");
93 ext1_engine2.layouts.push_back("jp");
94 ext1.engines.push_back(ext1_engine2);
96 ime_list_.push_back(ext1);
98 ComponentExtensionIME ext2;
99 ext2.id = "nmblnjkfdkabgdofidlkienfnnbjhnab";
100 ext2.description = "ext2_description";
101 ext2.path = base::FilePath("ext2_file_path");
103 ComponentExtensionEngine ext2_engine1;
104 ext2_engine1.engine_id = "ext2_engine1_engine_id";
105 ext2_engine1.display_name = "ext2_engine_1_display_name";
106 ext2_engine1.language_codes.push_back("en");
107 ext2_engine1.layouts.push_back("us");
108 ext2.engines.push_back(ext2_engine1);
110 ComponentExtensionEngine ext2_engine2;
111 ext2_engine2.engine_id = "ext2_engine2_engine_id";
112 ext2_engine2.display_name = "ext2_engine_2_display_name";
113 ext2_engine2.language_codes.push_back("en");
114 ext2_engine2.layouts.push_back("us(dvorak)");
115 ext2.engines.push_back(ext2_engine2);
117 ime_list_.push_back(ext2);
120 virtual void TearDown() OVERRIDE {
122 candidate_window_controller_ = NULL;
125 IMEBridge::Get()->SetCurrentEngineHandler(NULL);
126 IMEBridge::Shutdown();
130 // Helper function to initialize component extension stuff for testing.
131 void InitComponentExtension() {
132 mock_delegate_ = new MockComponentExtIMEManagerDelegate();
133 mock_delegate_->set_ime_list(ime_list_);
134 scoped_ptr<ComponentExtensionIMEManagerDelegate> delegate(mock_delegate_);
135 // Note, for production, these SetEngineHandler are called when
136 // IMEEngineHandlerInterface is initialized via
137 // InitializeComponentextension.
138 IMEBridge::Get()->SetEngineHandler(kNaclMozcUsId,
139 mock_engine_handler_.get());
140 IMEBridge::Get()->SetEngineHandler(kNaclMozcJpId,
141 mock_engine_handler_.get());
142 IMEBridge::Get()->SetEngineHandler(kExt2Engine1Id,
143 mock_engine_handler_.get());
144 IMEBridge::Get()->SetEngineHandler(kExt2Engine2Id,
145 mock_engine_handler_.get());
146 manager_->InitializeComponentExtensionForTesting(delegate.Pass());
149 scoped_ptr<InputMethodManagerImpl> manager_;
150 FakeInputMethodDelegate* delegate_;
151 MockCandidateWindowController* candidate_window_controller_;
152 scoped_ptr<MockIMEEngineHandler> mock_engine_handler_;
153 FakeXKeyboard* xkeyboard_;
154 base::MessageLoop message_loop_;
155 MockComponentExtIMEManagerDelegate* mock_delegate_;
156 std::vector<ComponentExtensionIME> ime_list_;
159 DISALLOW_COPY_AND_ASSIGN(InputMethodManagerImplTest);
162 class TestObserver : public InputMethodManager::Observer {
165 : input_method_changed_count_(0),
166 input_method_property_changed_count_(0),
167 last_show_message_(false) {
169 virtual ~TestObserver() {}
171 virtual void InputMethodChanged(InputMethodManager* manager,
172 bool show_message) OVERRIDE {
173 ++input_method_changed_count_;
174 last_show_message_ = show_message;
176 virtual void InputMethodPropertyChanged(
177 InputMethodManager* manager) OVERRIDE {
178 ++input_method_property_changed_count_;
181 int input_method_changed_count_;
182 int input_method_property_changed_count_;
183 bool last_show_message_;
186 DISALLOW_COPY_AND_ASSIGN(TestObserver);
189 class TestCandidateWindowObserver
190 : public InputMethodManager::CandidateWindowObserver {
192 TestCandidateWindowObserver()
193 : candidate_window_opened_count_(0),
194 candidate_window_closed_count_(0) {
196 virtual ~TestCandidateWindowObserver() {}
198 virtual void CandidateWindowOpened(InputMethodManager* manager) OVERRIDE {
199 ++candidate_window_opened_count_;
201 virtual void CandidateWindowClosed(InputMethodManager* manager) OVERRIDE {
202 ++candidate_window_closed_count_;
205 int candidate_window_opened_count_;
206 int candidate_window_closed_count_;
209 DISALLOW_COPY_AND_ASSIGN(TestCandidateWindowObserver);
213 TEST_F(InputMethodManagerImplTest, TestGetXKeyboard) {
214 EXPECT_TRUE(manager_->GetXKeyboard());
215 EXPECT_EQ(xkeyboard_, manager_->GetXKeyboard());
218 TEST_F(InputMethodManagerImplTest, TestCandidateWindowObserver) {
219 TestCandidateWindowObserver observer;
220 candidate_window_controller_->NotifyCandidateWindowOpened(); // nop
221 candidate_window_controller_->NotifyCandidateWindowClosed(); // nop
222 manager_->AddCandidateWindowObserver(&observer);
223 candidate_window_controller_->NotifyCandidateWindowOpened();
224 EXPECT_EQ(1, observer.candidate_window_opened_count_);
225 candidate_window_controller_->NotifyCandidateWindowClosed();
226 EXPECT_EQ(1, observer.candidate_window_closed_count_);
227 candidate_window_controller_->NotifyCandidateWindowOpened();
228 EXPECT_EQ(2, observer.candidate_window_opened_count_);
229 candidate_window_controller_->NotifyCandidateWindowClosed();
230 EXPECT_EQ(2, observer.candidate_window_closed_count_);
231 manager_->RemoveCandidateWindowObserver(&observer);
234 TEST_F(InputMethodManagerImplTest, TestObserver) {
235 // For http://crbug.com/19655#c11 - (3). browser_state_monitor_unittest.cc is
236 // also for the scenario.
237 std::vector<std::string> keyboard_layouts;
238 keyboard_layouts.push_back("xkb:us::eng");
240 TestObserver observer;
241 InitComponentExtension();
242 manager_->AddObserver(&observer);
243 EXPECT_EQ(0, observer.input_method_changed_count_);
244 manager_->EnableLoginLayouts("en-US", keyboard_layouts);
245 EXPECT_EQ(1, observer.input_method_changed_count_);
246 EXPECT_EQ(1, observer.input_method_property_changed_count_);
247 manager_->ChangeInputMethod("xkb:us:dvorak:eng");
248 EXPECT_FALSE(observer.last_show_message_);
249 EXPECT_EQ(2, observer.input_method_changed_count_);
250 EXPECT_EQ(2, observer.input_method_property_changed_count_);
251 manager_->ChangeInputMethod("xkb:us:dvorak:eng");
252 EXPECT_FALSE(observer.last_show_message_);
254 // The observer is always notified even when the same input method ID is
255 // passed to ChangeInputMethod() more than twice.
256 // TODO(komatsu): Revisit if this is neccessary.
257 EXPECT_EQ(3, observer.input_method_changed_count_);
259 // If the same input method ID is passed, PropertyChanged() is not
261 EXPECT_EQ(2, observer.input_method_property_changed_count_);
263 manager_->RemoveObserver(&observer);
266 TEST_F(InputMethodManagerImplTest, TestGetSupportedInputMethods) {
267 InitComponentExtension();
268 scoped_ptr<InputMethodDescriptors> methods(
269 manager_->GetSupportedInputMethods());
270 ASSERT_TRUE(methods.get());
271 // Try to find random 4-5 layuts and IMEs to make sure the returned list is
273 const InputMethodDescriptor* id_to_find =
274 manager_->GetInputMethodUtil()->GetInputMethodDescriptorFromId(
276 id_to_find = manager_->GetInputMethodUtil()->GetInputMethodDescriptorFromId(
278 EXPECT_TRUE(Contain(*methods.get(), *id_to_find));
279 id_to_find = manager_->GetInputMethodUtil()->GetInputMethodDescriptorFromId(
280 "xkb:us:dvorak:eng");
281 EXPECT_TRUE(Contain(*methods.get(), *id_to_find));
282 id_to_find = manager_->GetInputMethodUtil()->GetInputMethodDescriptorFromId(
284 EXPECT_TRUE(Contain(*methods.get(), *id_to_find));
287 TEST_F(InputMethodManagerImplTest, TestEnableLayouts) {
288 // Currently 5 keyboard layouts are supported for en-US, and 1 for ja. See
289 // ibus_input_method.txt.
290 std::vector<std::string> keyboard_layouts;
292 InitComponentExtension();
293 manager_->EnableLoginLayouts("en-US", keyboard_layouts);
294 EXPECT_EQ(5U, manager_->GetNumActiveInputMethods());
295 for (size_t i = 0; i < manager_->GetActiveInputMethodIds().size(); ++i)
296 LOG(ERROR) << manager_->GetActiveInputMethodIds().at(i);
298 // For http://crbug.com/19655#c11 - (5)
299 // The hardware keyboard layout "xkb:us::eng" is always active, hence 2U.
300 manager_->EnableLoginLayouts("ja", keyboard_layouts); // Japanese
301 EXPECT_EQ(2U, manager_->GetNumActiveInputMethods());
304 TEST_F(InputMethodManagerImplTest, TestEnableLayoutsAndCurrentInputMethod) {
305 // For http://crbug.com/329061
306 std::vector<std::string> keyboard_layouts;
307 keyboard_layouts.push_back("xkb:se::swe");
309 manager_->EnableLoginLayouts("en-US", keyboard_layouts);
310 const std::string im_id = manager_->GetCurrentInputMethod().id();
311 EXPECT_EQ("xkb:se::swe", im_id);
314 TEST_F(InputMethodManagerImplTest, TestEnableLayoutsNonUsHardwareKeyboard) {
315 // The physical layout is French.
316 manager_->GetInputMethodUtil()->SetHardwareKeyboardLayoutForTesting(
318 manager_->EnableLoginLayouts(
320 manager_->GetInputMethodUtil()->GetHardwareLoginInputMethodIds());
321 EXPECT_EQ(6U, manager_->GetNumActiveInputMethods()); // 5 + French
322 // The physical layout is Japanese.
323 manager_->GetInputMethodUtil()->SetHardwareKeyboardLayoutForTesting(
325 manager_->EnableLoginLayouts(
327 manager_->GetInputMethodUtil()->GetHardwareLoginInputMethodIds());
328 // "xkb:us::eng" is not needed, hence 1.
329 EXPECT_EQ(1U, manager_->GetNumActiveInputMethods());
331 // The physical layout is Russian.
332 manager_->GetInputMethodUtil()->SetHardwareKeyboardLayoutForTesting(
334 manager_->EnableLoginLayouts(
336 manager_->GetInputMethodUtil()->GetHardwareLoginInputMethodIds());
337 // "xkb:us::eng" only.
338 EXPECT_EQ(1U, manager_->GetNumActiveInputMethods());
339 EXPECT_EQ("xkb:us::eng", manager_->GetActiveInputMethodIds().front());
342 TEST_F(InputMethodManagerImplTest, TestEnableMultipleHardwareKeyboardLayout) {
343 // The physical layouts are French and Hungarian.
344 manager_->GetInputMethodUtil()->SetHardwareKeyboardLayoutForTesting(
345 "xkb:fr::fra,xkb:hu::hun");
346 manager_->EnableLoginLayouts(
348 manager_->GetInputMethodUtil()->GetHardwareLoginInputMethodIds());
349 // 5 + French + Hungarian
350 EXPECT_EQ(7U, manager_->GetNumActiveInputMethods());
353 TEST_F(InputMethodManagerImplTest,
354 TestEnableMultipleHardwareKeyboardLayout_NoLoginKeyboard) {
355 // The physical layouts are English (US) and Russian.
356 manager_->GetInputMethodUtil()->SetHardwareKeyboardLayoutForTesting(
357 "xkb:us::eng,xkb:ru::rus");
358 manager_->EnableLoginLayouts(
360 manager_->GetInputMethodUtil()->GetHardwareLoginInputMethodIds());
362 EXPECT_EQ(1U, manager_->GetNumActiveInputMethods());
365 TEST_F(InputMethodManagerImplTest, TestActiveInputMethods) {
366 std::vector<std::string> keyboard_layouts;
367 manager_->EnableLoginLayouts("ja", keyboard_layouts); // Japanese
368 EXPECT_EQ(2U, manager_->GetNumActiveInputMethods());
369 scoped_ptr<InputMethodDescriptors> methods(
370 manager_->GetActiveInputMethods());
371 ASSERT_TRUE(methods.get());
372 EXPECT_EQ(2U, methods->size());
373 const InputMethodDescriptor* id_to_find =
374 manager_->GetInputMethodUtil()->GetInputMethodDescriptorFromId(
376 EXPECT_TRUE(Contain(*methods.get(), *id_to_find));
377 id_to_find = manager_->GetInputMethodUtil()->GetInputMethodDescriptorFromId(
379 EXPECT_TRUE(Contain(*methods.get(), *id_to_find));
382 TEST_F(InputMethodManagerImplTest, TestEnableTwoLayouts) {
383 // For http://crbug.com/19655#c11 - (8), step 6.
384 TestObserver observer;
385 manager_->AddObserver(&observer);
386 InitComponentExtension();
387 manager_->SetState(InputMethodManager::STATE_BROWSER_SCREEN);
388 std::vector<std::string> ids;
389 ids.push_back("xkb:us:dvorak:eng");
390 ids.push_back("xkb:us:colemak:eng");
391 EXPECT_TRUE(manager_->ReplaceEnabledInputMethods(ids));
392 EXPECT_EQ(2U, manager_->GetNumActiveInputMethods());
393 // Since all the IDs added avobe are keyboard layouts, Start() should not be
395 EXPECT_EQ(1, observer.input_method_changed_count_);
396 EXPECT_EQ(ids[0], manager_->GetCurrentInputMethod().id());
397 EXPECT_EQ("us(dvorak)", xkeyboard_->last_layout_);
399 ids.erase(ids.begin());
400 EXPECT_TRUE(manager_->ReplaceEnabledInputMethods(ids));
401 EXPECT_EQ(1U, manager_->GetNumActiveInputMethods());
402 EXPECT_EQ(2, observer.input_method_changed_count_);
403 EXPECT_EQ(ids[0], // colemak
404 manager_->GetCurrentInputMethod().id());
405 EXPECT_EQ("us(colemak)", xkeyboard_->last_layout_);
406 manager_->RemoveObserver(&observer);
409 TEST_F(InputMethodManagerImplTest, TestEnableThreeLayouts) {
410 // For http://crbug.com/19655#c11 - (9).
411 TestObserver observer;
412 manager_->AddObserver(&observer);
413 InitComponentExtension();
414 manager_->SetState(InputMethodManager::STATE_BROWSER_SCREEN);
415 std::vector<std::string> ids;
416 ids.push_back("xkb:us::eng");
417 ids.push_back("xkb:us:dvorak:eng");
418 ids.push_back("xkb:us:colemak:eng");
419 EXPECT_TRUE(manager_->ReplaceEnabledInputMethods(ids));
420 EXPECT_EQ(3U, manager_->GetNumActiveInputMethods());
421 EXPECT_EQ(1, observer.input_method_changed_count_);
422 EXPECT_EQ(ids[0], manager_->GetCurrentInputMethod().id());
423 EXPECT_EQ("us", xkeyboard_->last_layout_);
425 manager_->SwitchToNextInputMethod();
426 EXPECT_EQ(2, observer.input_method_changed_count_);
427 EXPECT_EQ(ids[1], manager_->GetCurrentInputMethod().id());
428 EXPECT_EQ("us(dvorak)", xkeyboard_->last_layout_);
430 ids.erase(ids.begin() + 1);
431 EXPECT_TRUE(manager_->ReplaceEnabledInputMethods(ids));
432 EXPECT_EQ(2U, manager_->GetNumActiveInputMethods());
433 EXPECT_EQ(3, observer.input_method_changed_count_);
434 EXPECT_EQ(ids[0], // US Qwerty
435 manager_->GetCurrentInputMethod().id());
436 EXPECT_EQ("us", xkeyboard_->last_layout_);
437 manager_->RemoveObserver(&observer);
440 TEST_F(InputMethodManagerImplTest, TestEnableLayoutAndIme) {
441 // For http://crbug.com/19655#c11 - (10).
442 TestObserver observer;
443 manager_->AddObserver(&observer);
444 InitComponentExtension();
445 manager_->SetState(InputMethodManager::STATE_BROWSER_SCREEN);
446 std::vector<std::string> ids;
447 ids.push_back("xkb:us:dvorak:eng");
448 ids.push_back(kNaclMozcUsId);
449 EXPECT_TRUE(manager_->ReplaceEnabledInputMethods(ids));
450 EXPECT_EQ(1, observer.input_method_changed_count_);
451 EXPECT_EQ(ids[0], manager_->GetCurrentInputMethod().id());
452 EXPECT_EQ("us(dvorak)", xkeyboard_->last_layout_);
454 manager_->SwitchToNextInputMethod();
455 EXPECT_EQ(2, observer.input_method_changed_count_);
456 EXPECT_EQ(ids[1], manager_->GetCurrentInputMethod().id());
457 EXPECT_EQ("us", xkeyboard_->last_layout_);
459 ids.erase(ids.begin() + 1);
460 EXPECT_TRUE(manager_->ReplaceEnabledInputMethods(ids));
461 EXPECT_EQ(1U, manager_->GetNumActiveInputMethods());
462 EXPECT_EQ(ids[0], manager_->GetCurrentInputMethod().id());
463 EXPECT_EQ("us(dvorak)", xkeyboard_->last_layout_);
466 TEST_F(InputMethodManagerImplTest, TestEnableLayoutAndIme2) {
467 // For http://crbug.com/19655#c11 - (11).
468 TestObserver observer;
469 manager_->AddObserver(&observer);
470 InitComponentExtension();
471 manager_->SetState(InputMethodManager::STATE_BROWSER_SCREEN);
472 std::vector<std::string> ids;
473 ids.push_back("xkb:us:dvorak:eng");
474 ids.push_back(kNaclMozcUsId);
475 EXPECT_TRUE(manager_->ReplaceEnabledInputMethods(ids));
476 EXPECT_EQ(1, observer.input_method_changed_count_);
477 EXPECT_EQ(ids[0], manager_->GetCurrentInputMethod().id());
478 EXPECT_EQ("us(dvorak)", xkeyboard_->last_layout_);
481 ids.erase(ids.begin());
482 EXPECT_TRUE(manager_->ReplaceEnabledInputMethods(ids));
483 EXPECT_EQ(1U, manager_->GetNumActiveInputMethods());
484 EXPECT_EQ(ids[0], // Mozc
485 manager_->GetCurrentInputMethod().id());
486 EXPECT_EQ("us", xkeyboard_->last_layout_);
487 manager_->RemoveObserver(&observer);
490 TEST_F(InputMethodManagerImplTest, TestEnableImes) {
491 TestObserver observer;
492 manager_->AddObserver(&observer);
493 InitComponentExtension();
494 manager_->SetState(InputMethodManager::STATE_BROWSER_SCREEN);
495 std::vector<std::string> ids;
496 ids.push_back(kExt2Engine1Id);
497 ids.push_back("mozc-dv");
498 EXPECT_TRUE(manager_->ReplaceEnabledInputMethods(ids));
499 EXPECT_EQ(1, observer.input_method_changed_count_);
500 EXPECT_EQ(ids[0], manager_->GetCurrentInputMethod().id());
501 EXPECT_EQ("us", xkeyboard_->last_layout_);
502 manager_->RemoveObserver(&observer);
505 TEST_F(InputMethodManagerImplTest, TestEnableUnknownIds) {
506 TestObserver observer;
507 manager_->AddObserver(&observer);
508 manager_->SetState(InputMethodManager::STATE_BROWSER_SCREEN);
509 std::vector<std::string> ids;
510 ids.push_back("xkb:tl::tlh"); // Klingon, which is not supported.
511 ids.push_back("unknown-super-cool-ime");
512 EXPECT_FALSE(manager_->ReplaceEnabledInputMethods(ids));
514 // TODO(yusukes): Should we fall back to the hardware keyboard layout in this
516 EXPECT_EQ(0, observer.input_method_changed_count_);
518 manager_->RemoveObserver(&observer);
521 TEST_F(InputMethodManagerImplTest, TestEnableLayoutsThenLock) {
522 // For http://crbug.com/19655#c11 - (14).
523 TestObserver observer;
524 manager_->AddObserver(&observer);
525 InitComponentExtension();
526 manager_->SetState(InputMethodManager::STATE_BROWSER_SCREEN);
527 std::vector<std::string> ids;
528 ids.push_back("xkb:us::eng");
529 ids.push_back("xkb:us:dvorak:eng");
530 EXPECT_TRUE(manager_->ReplaceEnabledInputMethods(ids));
531 EXPECT_EQ(2U, manager_->GetNumActiveInputMethods());
532 EXPECT_EQ(1, observer.input_method_changed_count_);
533 EXPECT_EQ(ids[0], manager_->GetCurrentInputMethod().id());
534 EXPECT_EQ("us", xkeyboard_->last_layout_);
537 manager_->SwitchToNextInputMethod();
538 EXPECT_EQ(2, observer.input_method_changed_count_);
539 EXPECT_EQ(ids[1], manager_->GetCurrentInputMethod().id());
540 EXPECT_EQ("us(dvorak)", xkeyboard_->last_layout_);
543 manager_->SetState(InputMethodManager::STATE_LOCK_SCREEN);
544 EXPECT_EQ(2U, manager_->GetNumActiveInputMethods());
545 EXPECT_EQ(ids[1], // still Dvorak
546 manager_->GetCurrentInputMethod().id());
547 EXPECT_EQ("us(dvorak)", xkeyboard_->last_layout_);
548 // Switch back to Qwerty.
549 manager_->SwitchToNextInputMethod();
550 EXPECT_EQ(ids[0], manager_->GetCurrentInputMethod().id());
551 EXPECT_EQ("us", xkeyboard_->last_layout_);
553 // Unlock screen. The original state, Dvorak, is restored.
554 manager_->SetState(InputMethodManager::STATE_BROWSER_SCREEN);
555 EXPECT_EQ(2U, manager_->GetNumActiveInputMethods());
556 EXPECT_EQ(ids[1], manager_->GetCurrentInputMethod().id());
557 EXPECT_EQ("us(dvorak)", xkeyboard_->last_layout_);
559 manager_->RemoveObserver(&observer);
562 TEST_F(InputMethodManagerImplTest, SwitchInputMethodTest) {
563 // For http://crbug.com/19655#c11 - (15).
564 TestObserver observer;
565 manager_->AddObserver(&observer);
566 InitComponentExtension();
567 manager_->SetState(InputMethodManager::STATE_BROWSER_SCREEN);
568 std::vector<std::string> ids;
569 ids.push_back("xkb:us:dvorak:eng");
570 ids.push_back(kExt2Engine2Id);
571 ids.push_back(kExt2Engine1Id);
572 EXPECT_TRUE(manager_->ReplaceEnabledInputMethods(ids));
573 EXPECT_EQ(3U, manager_->GetNumActiveInputMethods());
574 EXPECT_EQ(1, observer.input_method_changed_count_);
575 EXPECT_EQ(ids[0], manager_->GetCurrentInputMethod().id());
576 EXPECT_EQ("us(dvorak)", xkeyboard_->last_layout_);
579 manager_->SwitchToNextInputMethod();
580 EXPECT_EQ(2, observer.input_method_changed_count_);
581 EXPECT_EQ(ids[1], manager_->GetCurrentInputMethod().id());
582 EXPECT_EQ("us(dvorak)", xkeyboard_->last_layout_);
585 manager_->SetState(InputMethodManager::STATE_LOCK_SCREEN);
586 EXPECT_EQ(2U, manager_->GetNumActiveInputMethods()); // Qwerty+Dvorak.
587 EXPECT_EQ("xkb:us:dvorak:eng",
588 manager_->GetCurrentInputMethod().id());
589 EXPECT_EQ("us(dvorak)", xkeyboard_->last_layout_);
590 manager_->SwitchToNextInputMethod();
591 EXPECT_EQ("xkb:us::eng", // The hardware keyboard layout.
592 manager_->GetCurrentInputMethod().id());
593 EXPECT_EQ("us", xkeyboard_->last_layout_);
595 // Unlock screen. The original state, pinyin-dv, is restored.
596 manager_->SetState(InputMethodManager::STATE_BROWSER_SCREEN);
597 EXPECT_EQ(3U, manager_->GetNumActiveInputMethods()); // Dvorak and 2 IMEs.
598 EXPECT_EQ(ids[1], manager_->GetCurrentInputMethod().id());
599 EXPECT_EQ("us(dvorak)", xkeyboard_->last_layout_);
601 manager_->RemoveObserver(&observer);
604 TEST_F(InputMethodManagerImplTest, TestXkbSetting) {
605 // For http://crbug.com/19655#c11 - (8), step 7-11.
606 InitComponentExtension();
607 manager_->SetState(InputMethodManager::STATE_BROWSER_SCREEN);
608 std::vector<std::string> ids;
609 ids.push_back("xkb:us:dvorak:eng");
610 ids.push_back("xkb:us:colemak:eng");
611 ids.push_back(kNaclMozcJpId);
612 ids.push_back(kNaclMozcUsId);
613 EXPECT_TRUE(manager_->ReplaceEnabledInputMethods(ids));
614 EXPECT_EQ(4U, manager_->GetNumActiveInputMethods());
615 EXPECT_EQ(1, xkeyboard_->set_current_keyboard_layout_by_name_count_);
616 // See input_methods.txt for an expected XKB layout name.
617 EXPECT_EQ("us(dvorak)", xkeyboard_->last_layout_);
618 manager_->SwitchToNextInputMethod();
619 EXPECT_EQ(2, xkeyboard_->set_current_keyboard_layout_by_name_count_);
620 EXPECT_EQ("us(colemak)", xkeyboard_->last_layout_);
621 manager_->SwitchToNextInputMethod();
622 EXPECT_EQ(3, xkeyboard_->set_current_keyboard_layout_by_name_count_);
623 EXPECT_EQ("jp", xkeyboard_->last_layout_);
624 manager_->SwitchToNextInputMethod();
625 EXPECT_EQ(4, xkeyboard_->set_current_keyboard_layout_by_name_count_);
626 EXPECT_EQ("us", xkeyboard_->last_layout_);
627 manager_->SwitchToNextInputMethod();
628 EXPECT_EQ(5, xkeyboard_->set_current_keyboard_layout_by_name_count_);
629 EXPECT_EQ("us(dvorak)", xkeyboard_->last_layout_);
631 ids.erase(ids.begin());
632 EXPECT_TRUE(manager_->ReplaceEnabledInputMethods(ids));
633 EXPECT_EQ(3U, manager_->GetNumActiveInputMethods());
634 EXPECT_EQ(6, xkeyboard_->set_current_keyboard_layout_by_name_count_);
635 EXPECT_EQ("us(colemak)", xkeyboard_->last_layout_);
638 TEST_F(InputMethodManagerImplTest, TestActivateInputMethodProperty) {
639 const std::string kKey = "key";
640 InputMethodPropertyList property_list;
641 property_list.push_back(InputMethodProperty(kKey, "label", false, false));
642 manager_->SetCurrentInputMethodProperties(property_list);
644 manager_->ActivateInputMethodProperty(kKey);
645 EXPECT_EQ(kKey, mock_engine_handler_->last_activated_property());
647 // Key2 is not registered, so activated property should not be changed.
648 manager_->ActivateInputMethodProperty("key2");
649 EXPECT_EQ(kKey, mock_engine_handler_->last_activated_property());
652 TEST_F(InputMethodManagerImplTest, TestGetCurrentInputMethodProperties) {
653 InitComponentExtension();
654 EXPECT_TRUE(manager_->GetCurrentInputMethodProperties().empty());
656 manager_->SetState(InputMethodManager::STATE_BROWSER_SCREEN);
657 std::vector<std::string> ids;
658 ids.push_back("xkb:us::eng");
659 ids.push_back(kNaclMozcUsId);
660 EXPECT_TRUE(manager_->ReplaceEnabledInputMethods(ids));
661 EXPECT_EQ(2U, manager_->GetNumActiveInputMethods());
662 EXPECT_TRUE(manager_->GetCurrentInputMethodProperties().empty());
663 manager_->ChangeInputMethod(kNaclMozcUsId);
665 InputMethodPropertyList current_property_list;
666 current_property_list.push_back(InputMethodProperty("key",
670 manager_->SetCurrentInputMethodProperties(current_property_list);
672 ASSERT_EQ(1U, manager_->GetCurrentInputMethodProperties().size());
673 EXPECT_EQ("key", manager_->GetCurrentInputMethodProperties().at(0).key);
675 manager_->ChangeInputMethod("xkb:us::eng");
676 EXPECT_TRUE(manager_->GetCurrentInputMethodProperties().empty());
679 TEST_F(InputMethodManagerImplTest, TestGetCurrentInputMethodPropertiesTwoImes) {
680 InitComponentExtension();
681 EXPECT_TRUE(manager_->GetCurrentInputMethodProperties().empty());
683 manager_->SetState(InputMethodManager::STATE_BROWSER_SCREEN);
684 std::vector<std::string> ids;
685 ids.push_back(kNaclMozcUsId); // Japanese
686 ids.push_back(kExt2Engine1Id); // T-Chinese
687 EXPECT_TRUE(manager_->ReplaceEnabledInputMethods(ids));
688 EXPECT_EQ(2U, manager_->GetNumActiveInputMethods());
689 EXPECT_TRUE(manager_->GetCurrentInputMethodProperties().empty());
691 InputMethodPropertyList current_property_list;
692 current_property_list.push_back(InputMethodProperty("key-mozc",
696 manager_->SetCurrentInputMethodProperties(current_property_list);
698 ASSERT_EQ(1U, manager_->GetCurrentInputMethodProperties().size());
699 EXPECT_EQ("key-mozc", manager_->GetCurrentInputMethodProperties().at(0).key);
701 manager_->ChangeInputMethod(kExt2Engine1Id);
702 // Since the IME is changed, the property for mozc Japanese should be hidden.
703 EXPECT_TRUE(manager_->GetCurrentInputMethodProperties().empty());
705 // Asynchronous property update signal from mozc-chewing.
706 current_property_list.clear();
707 current_property_list.push_back(InputMethodProperty("key-chewing",
711 manager_->SetCurrentInputMethodProperties(current_property_list);
712 ASSERT_EQ(1U, manager_->GetCurrentInputMethodProperties().size());
713 EXPECT_EQ("key-chewing",
714 manager_->GetCurrentInputMethodProperties().at(0).key);
717 TEST_F(InputMethodManagerImplTest, TestNextInputMethod) {
718 TestObserver observer;
719 manager_->AddObserver(&observer);
720 InitComponentExtension();
721 std::vector<std::string> keyboard_layouts;
722 keyboard_layouts.push_back("xkb:us::eng");
723 // For http://crbug.com/19655#c11 - (1)
724 manager_->EnableLoginLayouts("en-US", keyboard_layouts);
725 EXPECT_EQ(5U, manager_->GetNumActiveInputMethods());
726 EXPECT_EQ("xkb:us::eng", manager_->GetCurrentInputMethod().id());
727 EXPECT_EQ("us", xkeyboard_->last_layout_);
728 manager_->SwitchToNextInputMethod();
729 EXPECT_TRUE(observer.last_show_message_);
730 EXPECT_EQ("xkb:us:intl:eng", manager_->GetCurrentInputMethod().id());
731 EXPECT_EQ("us(intl)", xkeyboard_->last_layout_);
732 manager_->SwitchToNextInputMethod();
733 EXPECT_TRUE(observer.last_show_message_);
734 EXPECT_EQ("xkb:us:altgr-intl:eng", manager_->GetCurrentInputMethod().id());
735 EXPECT_EQ("us(altgr-intl)", xkeyboard_->last_layout_);
736 manager_->SwitchToNextInputMethod();
737 EXPECT_TRUE(observer.last_show_message_);
738 EXPECT_EQ("xkb:us:dvorak:eng", manager_->GetCurrentInputMethod().id());
739 EXPECT_EQ("us(dvorak)", xkeyboard_->last_layout_);
740 manager_->SwitchToNextInputMethod();
741 EXPECT_TRUE(observer.last_show_message_);
742 EXPECT_EQ("xkb:us:colemak:eng", manager_->GetCurrentInputMethod().id());
743 EXPECT_EQ("us(colemak)", xkeyboard_->last_layout_);
744 manager_->SwitchToNextInputMethod();
745 EXPECT_TRUE(observer.last_show_message_);
746 EXPECT_EQ("xkb:us::eng", manager_->GetCurrentInputMethod().id());
747 EXPECT_EQ("us", xkeyboard_->last_layout_);
749 manager_->RemoveObserver(&observer);
752 TEST_F(InputMethodManagerImplTest, TestPreviousInputMethod) {
753 TestObserver observer;
754 manager_->AddObserver(&observer);
755 InitComponentExtension();
757 ui::Accelerator keydown_accelerator(ui::VKEY_SPACE, ui::EF_CONTROL_DOWN);
758 keydown_accelerator.set_type(ui::ET_KEY_PRESSED);
759 ui::Accelerator keyup_accelerator(ui::VKEY_SPACE, ui::EF_CONTROL_DOWN);
760 keyup_accelerator.set_type(ui::ET_KEY_RELEASED);
762 std::vector<std::string> keyboard_layouts;
763 keyboard_layouts.push_back("xkb:us::eng");
764 manager_->EnableLoginLayouts("en-US", keyboard_layouts);
765 EXPECT_EQ(5U, manager_->GetNumActiveInputMethods());
766 EXPECT_EQ("xkb:us::eng", manager_->GetCurrentInputMethod().id());
767 EXPECT_EQ("us", xkeyboard_->last_layout_);
768 EXPECT_TRUE(manager_->SwitchToNextInputMethod());
769 EXPECT_TRUE(observer.last_show_message_);
770 EXPECT_EQ("xkb:us:intl:eng", manager_->GetCurrentInputMethod().id());
771 EXPECT_EQ("us(intl)", xkeyboard_->last_layout_);
772 EXPECT_TRUE(manager_->SwitchToPreviousInputMethod(keydown_accelerator));
773 EXPECT_TRUE(manager_->SwitchToPreviousInputMethod(keyup_accelerator));
774 EXPECT_TRUE(observer.last_show_message_);
775 EXPECT_EQ("xkb:us::eng", manager_->GetCurrentInputMethod().id());
776 EXPECT_EQ("us", xkeyboard_->last_layout_);
777 EXPECT_TRUE(manager_->SwitchToPreviousInputMethod(keydown_accelerator));
778 EXPECT_TRUE(manager_->SwitchToPreviousInputMethod(keyup_accelerator));
779 EXPECT_TRUE(observer.last_show_message_);
780 EXPECT_EQ("xkb:us:intl:eng", manager_->GetCurrentInputMethod().id());
781 EXPECT_EQ("us(intl)", xkeyboard_->last_layout_);
782 EXPECT_TRUE(manager_->SwitchToPreviousInputMethod(keydown_accelerator));
783 EXPECT_TRUE(manager_->SwitchToPreviousInputMethod(keyup_accelerator));
784 EXPECT_TRUE(observer.last_show_message_);
785 EXPECT_EQ("xkb:us::eng", manager_->GetCurrentInputMethod().id());
786 EXPECT_EQ("us", xkeyboard_->last_layout_);
787 EXPECT_TRUE(manager_->SwitchToNextInputMethod());
788 EXPECT_TRUE(observer.last_show_message_);
789 EXPECT_EQ("xkb:us:intl:eng", manager_->GetCurrentInputMethod().id());
790 EXPECT_EQ("us(intl)", xkeyboard_->last_layout_);
791 EXPECT_TRUE(manager_->SwitchToNextInputMethod());
792 EXPECT_TRUE(observer.last_show_message_);
793 EXPECT_EQ("xkb:us:altgr-intl:eng", manager_->GetCurrentInputMethod().id());
794 EXPECT_EQ("us(altgr-intl)", xkeyboard_->last_layout_);
795 EXPECT_TRUE(manager_->SwitchToPreviousInputMethod(keydown_accelerator));
796 EXPECT_TRUE(manager_->SwitchToPreviousInputMethod(keyup_accelerator));
797 EXPECT_TRUE(observer.last_show_message_);
798 EXPECT_EQ("xkb:us:intl:eng", manager_->GetCurrentInputMethod().id());
799 EXPECT_EQ("us(intl)", xkeyboard_->last_layout_);
800 EXPECT_TRUE(manager_->SwitchToPreviousInputMethod(keydown_accelerator));
801 EXPECT_TRUE(manager_->SwitchToPreviousInputMethod(keyup_accelerator));
802 EXPECT_TRUE(observer.last_show_message_);
803 EXPECT_EQ("xkb:us:altgr-intl:eng", manager_->GetCurrentInputMethod().id());
804 EXPECT_EQ("us(altgr-intl)", xkeyboard_->last_layout_);
806 manager_->RemoveObserver(&observer);
809 TEST_F(InputMethodManagerImplTest,
810 TestSwitchToPreviousInputMethodForOneActiveInputMethod) {
811 TestObserver observer;
812 manager_->AddObserver(&observer);
813 InitComponentExtension();
815 ui::Accelerator keydown_accelerator(ui::VKEY_SPACE, ui::EF_CONTROL_DOWN);
816 keydown_accelerator.set_type(ui::ET_KEY_PRESSED);
817 ui::Accelerator keyup_accelerator(ui::VKEY_SPACE, ui::EF_CONTROL_DOWN);
818 keyup_accelerator.set_type(ui::ET_KEY_RELEASED);
820 std::vector<std::string> ids;
821 ids.push_back("xkb:us:dvorak:eng");
822 EXPECT_TRUE(manager_->ReplaceEnabledInputMethods(ids));
823 EXPECT_EQ(1U, manager_->GetNumActiveInputMethods());
825 // Ctrl+Space accelerator should not be consumed if there is only one active
827 EXPECT_FALSE(manager_->SwitchToPreviousInputMethod(keydown_accelerator));
828 EXPECT_FALSE(manager_->SwitchToPreviousInputMethod(keyup_accelerator));
830 manager_->RemoveObserver(&observer);
833 TEST_F(InputMethodManagerImplTest, TestSwitchInputMethodWithUsLayouts) {
834 TestObserver observer;
835 manager_->AddObserver(&observer);
836 InitComponentExtension();
837 std::vector<std::string> keyboard_layouts;
838 keyboard_layouts.push_back("xkb:us::eng");
839 manager_->EnableLoginLayouts("en-US", keyboard_layouts);
840 EXPECT_EQ(5U, manager_->GetNumActiveInputMethods());
841 EXPECT_EQ("xkb:us::eng", manager_->GetCurrentInputMethod().id());
842 EXPECT_EQ("us", xkeyboard_->last_layout_);
844 // Henkan, Muhenkan, ZenkakuHankaku should be ignored when no Japanese IMEs
845 // and keyboards are enabled.
846 EXPECT_FALSE(manager_->SwitchInputMethod(
847 ui::Accelerator(ui::VKEY_CONVERT, ui::EF_NONE)));
848 EXPECT_FALSE(observer.last_show_message_);
849 EXPECT_EQ("xkb:us::eng", manager_->GetCurrentInputMethod().id());
850 EXPECT_EQ("us", xkeyboard_->last_layout_);
851 EXPECT_FALSE(manager_->SwitchInputMethod(
852 ui::Accelerator(ui::VKEY_NONCONVERT, ui::EF_NONE)));
853 EXPECT_EQ("xkb:us::eng", manager_->GetCurrentInputMethod().id());
854 EXPECT_EQ("us", xkeyboard_->last_layout_);
855 EXPECT_FALSE(manager_->SwitchInputMethod(
856 ui::Accelerator(ui::VKEY_DBE_SBCSCHAR, ui::EF_NONE)));
857 EXPECT_EQ("xkb:us::eng", manager_->GetCurrentInputMethod().id());
858 EXPECT_EQ("us", xkeyboard_->last_layout_);
859 EXPECT_FALSE(manager_->SwitchInputMethod(
860 ui::Accelerator(ui::VKEY_DBE_DBCSCHAR, ui::EF_NONE)));
861 EXPECT_EQ("xkb:us::eng", manager_->GetCurrentInputMethod().id());
862 EXPECT_EQ("us", xkeyboard_->last_layout_);
864 manager_->RemoveObserver(&observer);
867 TEST_F(InputMethodManagerImplTest, TestSwitchInputMethodWithJpLayout) {
868 // Enable "xkb:jp::jpn" and press Muhenkan/ZenkakuHankaku.
869 InitComponentExtension();
871 ui::Accelerator keydown_accelerator(ui::VKEY_SPACE, ui::EF_CONTROL_DOWN);
872 keydown_accelerator.set_type(ui::ET_KEY_PRESSED);
873 ui::Accelerator keyup_accelerator(ui::VKEY_SPACE, ui::EF_CONTROL_DOWN);
874 keyup_accelerator.set_type(ui::ET_KEY_RELEASED);
876 std::vector<std::string> keyboard_layouts;
877 keyboard_layouts.push_back("xkb:us::eng");
878 manager_->EnableLoginLayouts("ja", keyboard_layouts);
879 EXPECT_EQ(2U, manager_->GetNumActiveInputMethods());
880 EXPECT_EQ("xkb:us::eng", manager_->GetCurrentInputMethod().id());
881 EXPECT_EQ("us", xkeyboard_->last_layout_);
882 EXPECT_TRUE(manager_->SwitchInputMethod(
883 ui::Accelerator(ui::VKEY_NONCONVERT, ui::EF_NONE)));
884 EXPECT_EQ("xkb:jp::jpn", manager_->GetCurrentInputMethod().id());
885 EXPECT_EQ("jp", xkeyboard_->last_layout_);
886 EXPECT_TRUE(manager_->SwitchToPreviousInputMethod(keydown_accelerator));
887 EXPECT_TRUE(manager_->SwitchToPreviousInputMethod(keyup_accelerator));
888 EXPECT_EQ("xkb:us::eng", manager_->GetCurrentInputMethod().id());
889 EXPECT_EQ("us", xkeyboard_->last_layout_);
890 EXPECT_TRUE(manager_->SwitchInputMethod(
891 ui::Accelerator(ui::VKEY_DBE_SBCSCHAR, ui::EF_NONE)));
892 EXPECT_EQ("xkb:jp::jpn", manager_->GetCurrentInputMethod().id());
893 EXPECT_EQ("jp", xkeyboard_->last_layout_);
894 EXPECT_TRUE(manager_->SwitchToPreviousInputMethod(keydown_accelerator));
895 EXPECT_TRUE(manager_->SwitchToPreviousInputMethod(keyup_accelerator));
896 EXPECT_EQ("xkb:us::eng", manager_->GetCurrentInputMethod().id());
897 EXPECT_EQ("us", xkeyboard_->last_layout_);
898 EXPECT_TRUE(manager_->SwitchInputMethod(
899 ui::Accelerator(ui::VKEY_DBE_DBCSCHAR, ui::EF_NONE)));
900 EXPECT_EQ("xkb:jp::jpn", manager_->GetCurrentInputMethod().id());
901 EXPECT_EQ("jp", xkeyboard_->last_layout_);
904 TEST_F(InputMethodManagerImplTest, TestSwitchInputMethodWithJpIme) {
905 InitComponentExtension();
906 manager_->SetState(InputMethodManager::STATE_BROWSER_SCREEN);
907 std::vector<std::string> ids;
908 ids.push_back("xkb:jp::jpn");
909 ids.push_back(kNaclMozcJpId);
910 EXPECT_TRUE(manager_->ReplaceEnabledInputMethods(ids));
911 EXPECT_EQ("xkb:jp::jpn", manager_->GetCurrentInputMethod().id());
912 EXPECT_EQ("jp", xkeyboard_->last_layout_);
913 EXPECT_TRUE(manager_->SwitchInputMethod(
914 ui::Accelerator(ui::VKEY_DBE_DBCSCHAR, ui::EF_NONE)));
915 EXPECT_EQ(kNaclMozcJpId, manager_->GetCurrentInputMethod().id());
916 EXPECT_EQ("jp", xkeyboard_->last_layout_);
917 EXPECT_TRUE(manager_->SwitchInputMethod(
918 ui::Accelerator(ui::VKEY_DBE_DBCSCHAR, ui::EF_NONE)));
919 EXPECT_EQ("xkb:jp::jpn", manager_->GetCurrentInputMethod().id());
920 EXPECT_EQ("jp", xkeyboard_->last_layout_);
921 EXPECT_TRUE(manager_->SwitchInputMethod(
922 ui::Accelerator(ui::VKEY_CONVERT, ui::EF_NONE)));
923 EXPECT_EQ(kNaclMozcJpId, manager_->GetCurrentInputMethod().id());
924 EXPECT_EQ("jp", xkeyboard_->last_layout_);
925 EXPECT_TRUE(manager_->SwitchInputMethod(
926 ui::Accelerator(ui::VKEY_CONVERT, ui::EF_NONE)));
927 EXPECT_EQ(kNaclMozcJpId, manager_->GetCurrentInputMethod().id());
928 EXPECT_EQ("jp", xkeyboard_->last_layout_);
929 EXPECT_TRUE(manager_->SwitchInputMethod(
930 ui::Accelerator(ui::VKEY_NONCONVERT, ui::EF_NONE)));
931 EXPECT_EQ("xkb:jp::jpn", manager_->GetCurrentInputMethod().id());
932 EXPECT_EQ("jp", xkeyboard_->last_layout_);
933 EXPECT_TRUE(manager_->SwitchInputMethod(
934 ui::Accelerator(ui::VKEY_NONCONVERT, ui::EF_NONE)));
935 EXPECT_EQ("xkb:jp::jpn", manager_->GetCurrentInputMethod().id());
936 EXPECT_EQ("jp", xkeyboard_->last_layout_);
939 ids.push_back("xkb:us:dvorak:eng");
940 EXPECT_TRUE(manager_->ReplaceEnabledInputMethods(ids));
941 EXPECT_EQ("xkb:jp::jpn", manager_->GetCurrentInputMethod().id());
942 EXPECT_EQ("jp", xkeyboard_->last_layout_);
943 EXPECT_TRUE(manager_->SwitchInputMethod(
944 ui::Accelerator(ui::VKEY_DBE_SBCSCHAR, ui::EF_NONE)));
945 EXPECT_EQ(kNaclMozcJpId, manager_->GetCurrentInputMethod().id());
946 EXPECT_EQ("jp", xkeyboard_->last_layout_);
947 EXPECT_TRUE(manager_->SwitchInputMethod(
948 ui::Accelerator(ui::VKEY_DBE_SBCSCHAR, ui::EF_NONE)));
949 EXPECT_EQ("xkb:jp::jpn", manager_->GetCurrentInputMethod().id());
950 EXPECT_EQ("jp", xkeyboard_->last_layout_);
953 TEST_F(InputMethodManagerImplTest, TestAddRemoveExtensionInputMethods) {
954 TestObserver observer;
955 manager_->AddObserver(&observer);
956 InitComponentExtension();
957 manager_->SetState(InputMethodManager::STATE_BROWSER_SCREEN);
958 std::vector<std::string> ids;
959 ids.push_back("xkb:us:dvorak:eng");
960 EXPECT_TRUE(manager_->ReplaceEnabledInputMethods(ids));
961 EXPECT_EQ(1U, manager_->GetNumActiveInputMethods());
962 EXPECT_EQ(1, observer.input_method_changed_count_);
964 manager_->GetCurrentInputMethod().id());
965 EXPECT_EQ("us(dvorak)", xkeyboard_->last_layout_);
967 // Add two Extension IMEs.
968 std::vector<std::string> layouts;
969 layouts.push_back("us");
970 std::vector<std::string> languages;
971 languages.push_back("en-US");
973 const std::string ext1_id =
974 extension_ime_util::GetInputMethodID("deadbeef", "engine_id");
975 const InputMethodDescriptor descriptor1(ext1_id,
976 "deadbeef input method",
980 false, // is_login_keyboard
983 MockInputMethodEngine engine(descriptor1);
984 manager_->AddInputMethodExtension(ext1_id, &engine);
986 // Extension IMEs are not enabled by default.
987 EXPECT_EQ(1U, manager_->GetNumActiveInputMethods());
989 std::vector<std::string> extension_ime_ids;
990 extension_ime_ids.push_back(ext1_id);
991 manager_->SetEnabledExtensionImes(&extension_ime_ids);
992 EXPECT_EQ(2U, manager_->GetNumActiveInputMethods());
995 scoped_ptr<InputMethodDescriptors> methods(
996 manager_->GetActiveInputMethods());
997 ASSERT_EQ(2U, methods->size());
998 // Ext IMEs should be at the end of the list.
999 EXPECT_EQ(ext1_id, methods->at(1).id());
1002 const std::string ext2_id =
1003 extension_ime_util::GetInputMethodID("cafebabe", "engine_id");
1004 const InputMethodDescriptor descriptor2(ext2_id,
1005 "cafebabe input method",
1009 false, // is_login_keyboard
1012 MockInputMethodEngine engine2(descriptor2);
1013 manager_->AddInputMethodExtension(ext2_id, &engine2);
1014 EXPECT_EQ(2U, manager_->GetNumActiveInputMethods());
1016 extension_ime_ids.push_back(ext2_id);
1017 manager_->SetEnabledExtensionImes(&extension_ime_ids);
1018 EXPECT_EQ(3U, manager_->GetNumActiveInputMethods());
1020 scoped_ptr<InputMethodDescriptors> methods(
1021 manager_->GetActiveInputMethods());
1022 ASSERT_EQ(3U, methods->size());
1023 // Ext IMEs should be at the end of the list.
1024 EXPECT_EQ(ext1_id, methods->at(1).id());
1025 EXPECT_EQ(ext2_id, methods->at(2).id());
1029 manager_->RemoveInputMethodExtension(ext1_id);
1030 EXPECT_EQ(2U, manager_->GetNumActiveInputMethods());
1031 manager_->RemoveInputMethodExtension(ext2_id);
1032 EXPECT_EQ(1U, manager_->GetNumActiveInputMethods());
1035 TEST_F(InputMethodManagerImplTest, TestAddExtensionInputThenLockScreen) {
1036 TestObserver observer;
1037 InitComponentExtension();
1038 manager_->AddObserver(&observer);
1039 manager_->SetState(InputMethodManager::STATE_BROWSER_SCREEN);
1040 std::vector<std::string> ids;
1041 ids.push_back("xkb:us::eng");
1042 EXPECT_TRUE(manager_->ReplaceEnabledInputMethods(ids));
1043 EXPECT_EQ(1U, manager_->GetNumActiveInputMethods());
1044 EXPECT_EQ(1, observer.input_method_changed_count_);
1045 EXPECT_EQ(ids[0], manager_->GetCurrentInputMethod().id());
1046 EXPECT_EQ("us", xkeyboard_->last_layout_);
1048 // Add an Extension IME.
1049 std::vector<std::string> layouts;
1050 layouts.push_back("us(dvorak)");
1051 std::vector<std::string> languages;
1052 languages.push_back("en-US");
1054 const std::string ext_id =
1055 extension_ime_util::GetInputMethodID("deadbeef", "engine_id");
1056 const InputMethodDescriptor descriptor(ext_id,
1057 "deadbeef input method",
1061 false, // is_login_keyboard
1064 MockInputMethodEngine engine(descriptor);
1065 manager_->AddInputMethodExtension(ext_id, &engine);
1067 // Extension IME is not enabled by default.
1068 EXPECT_EQ(1U, manager_->GetNumActiveInputMethods());
1069 EXPECT_EQ(1, observer.input_method_changed_count_);
1071 std::vector<std::string> extension_ime_ids;
1072 extension_ime_ids.push_back(ext_id);
1073 manager_->SetEnabledExtensionImes(&extension_ime_ids);
1074 EXPECT_EQ(2U, manager_->GetNumActiveInputMethods());
1076 // Switch to the IME.
1077 manager_->SwitchToNextInputMethod();
1078 EXPECT_EQ(3, observer.input_method_changed_count_);
1079 EXPECT_EQ(ext_id, manager_->GetCurrentInputMethod().id());
1080 EXPECT_EQ("us(dvorak)", xkeyboard_->last_layout_);
1082 // Lock the screen. This is for crosbug.com/27049.
1083 manager_->SetState(InputMethodManager::STATE_LOCK_SCREEN);
1084 EXPECT_EQ(1U, manager_->GetNumActiveInputMethods()); // Qwerty. No Ext. IME
1085 EXPECT_EQ("xkb:us::eng",
1086 manager_->GetCurrentInputMethod().id());
1087 EXPECT_EQ("us", xkeyboard_->last_layout_);
1089 // Unlock the screen.
1090 manager_->SetState(InputMethodManager::STATE_BROWSER_SCREEN);
1091 EXPECT_EQ(2U, manager_->GetNumActiveInputMethods());
1092 EXPECT_EQ(ext_id, manager_->GetCurrentInputMethod().id());
1093 EXPECT_EQ("us(dvorak)", xkeyboard_->last_layout_);
1095 // This is for crosbug.com/27052.
1096 scoped_ptr<InputMethodDescriptors> methods(
1097 manager_->GetActiveInputMethods());
1098 ASSERT_EQ(2U, methods->size());
1099 // Ext. IMEs should be at the end of the list.
1100 EXPECT_EQ(ext_id, methods->at(1).id());
1102 manager_->RemoveObserver(&observer);
1105 TEST_F(InputMethodManagerImplTest,
1106 ChangeInputMethodBeforeComponentExtensionInitialization_OneIME) {
1107 manager_->SetState(InputMethodManager::STATE_BROWSER_SCREEN);
1108 std::vector<std::string> ids;
1109 ids.push_back(kNaclMozcUsId);
1110 EXPECT_TRUE(manager_->ReplaceEnabledInputMethods(ids));
1111 EXPECT_EQ(1U, manager_->GetNumActiveInputMethods());
1112 manager_->ChangeInputMethod(kNaclMozcUsId);
1114 InitComponentExtension();
1115 EXPECT_EQ(kNaclMozcUsId, manager_->GetCurrentInputMethod().id());
1118 TEST_F(InputMethodManagerImplTest,
1119 ChangeInputMethodBeforeComponentExtensionInitialization_TwoIME) {
1120 manager_->SetState(InputMethodManager::STATE_BROWSER_SCREEN);
1121 std::vector<std::string> ids;
1122 ids.push_back(kNaclMozcUsId);
1123 ids.push_back(kNaclMozcJpId);
1124 EXPECT_TRUE(manager_->ReplaceEnabledInputMethods(ids));
1125 EXPECT_EQ(2U, manager_->GetNumActiveInputMethods());
1126 manager_->ChangeInputMethod(kNaclMozcUsId);
1127 manager_->ChangeInputMethod(kNaclMozcJpId);
1129 InitComponentExtension();
1130 EXPECT_EQ(kNaclMozcJpId, manager_->GetCurrentInputMethod().id());
1133 TEST_F(InputMethodManagerImplTest,
1134 ChangeInputMethodBeforeComponentExtensionInitialization_CompOneIME) {
1135 manager_->SetState(InputMethodManager::STATE_BROWSER_SCREEN);
1136 const std::string ext_id = extension_ime_util::GetComponentInputMethodID(
1138 ime_list_[0].engines[0].engine_id);
1139 std::vector<std::string> ids;
1140 ids.push_back(ext_id);
1141 EXPECT_TRUE(manager_->ReplaceEnabledInputMethods(ids));
1142 EXPECT_EQ(1U, manager_->GetNumActiveInputMethods());
1143 manager_->ChangeInputMethod(ext_id);
1145 InitComponentExtension();
1146 EXPECT_EQ(ext_id, manager_->GetCurrentInputMethod().id());
1149 TEST_F(InputMethodManagerImplTest,
1150 ChangeInputMethodBeforeComponentExtensionInitialization_CompTwoIME) {
1151 manager_->SetState(InputMethodManager::STATE_BROWSER_SCREEN);
1152 const std::string ext_id1 = extension_ime_util::GetComponentInputMethodID(
1154 ime_list_[0].engines[0].engine_id);
1155 const std::string ext_id2 = extension_ime_util::GetComponentInputMethodID(
1157 ime_list_[1].engines[0].engine_id);
1158 std::vector<std::string> ids;
1159 ids.push_back(ext_id1);
1160 ids.push_back(ext_id2);
1161 EXPECT_TRUE(manager_->ReplaceEnabledInputMethods(ids));
1162 EXPECT_EQ(2U, manager_->GetNumActiveInputMethods());
1163 manager_->ChangeInputMethod(ext_id1);
1164 manager_->ChangeInputMethod(ext_id2);
1166 InitComponentExtension();
1167 EXPECT_EQ(ext_id2, manager_->GetCurrentInputMethod().id());
1170 TEST_F(InputMethodManagerImplTest,
1171 ChangeInputMethod_ComponenteExtensionOneIME) {
1172 InitComponentExtension();
1173 manager_->SetState(InputMethodManager::STATE_BROWSER_SCREEN);
1174 const std::string ext_id = extension_ime_util::GetComponentInputMethodID(
1176 ime_list_[0].engines[0].engine_id);
1177 std::vector<std::string> ids;
1178 ids.push_back(ext_id);
1179 EXPECT_TRUE(manager_->ReplaceEnabledInputMethods(ids));
1180 EXPECT_EQ(1U, manager_->GetNumActiveInputMethods());
1181 EXPECT_EQ(ext_id, manager_->GetCurrentInputMethod().id());
1184 TEST_F(InputMethodManagerImplTest,
1185 ChangeInputMethod_ComponenteExtensionTwoIME) {
1186 InitComponentExtension();
1187 manager_->SetState(InputMethodManager::STATE_BROWSER_SCREEN);
1188 const std::string ext_id1 = extension_ime_util::GetComponentInputMethodID(
1190 ime_list_[0].engines[0].engine_id);
1191 const std::string ext_id2 = extension_ime_util::GetComponentInputMethodID(
1193 ime_list_[1].engines[0].engine_id);
1194 std::vector<std::string> ids;
1195 ids.push_back(ext_id1);
1196 ids.push_back(ext_id2);
1197 EXPECT_TRUE(manager_->ReplaceEnabledInputMethods(ids));
1198 EXPECT_EQ(2U, manager_->GetNumActiveInputMethods());
1199 EXPECT_EQ(ext_id1, manager_->GetCurrentInputMethod().id());
1200 manager_->ChangeInputMethod(ext_id2);
1201 EXPECT_EQ(ext_id2, manager_->GetCurrentInputMethod().id());
1204 } // namespace input_method
1205 } // namespace chromeos