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/mock_candidate_window_controller.h"
17 #include "chrome/browser/chromeos/input_method/mock_ibus_controller.h"
18 #include "chromeos/dbus/fake_dbus_thread_manager.h"
19 #include "chromeos/dbus/ibus/mock_ibus_client.h"
20 #include "chromeos/ime/extension_ime_util.h"
21 #include "chromeos/ime/fake_input_method_delegate.h"
22 #include "chromeos/ime/mock_component_extension_ime_manager_delegate.h"
23 #include "chromeos/ime/mock_ibus_daemon_controller.h"
24 #include "chromeos/ime/mock_ime_engine_handler.h"
25 #include "chromeos/ime/mock_xkeyboard.h"
26 #include "testing/gtest/include/gtest/gtest.h"
27 #include "ui/base/accelerators/accelerator.h"
28 #include "ui/events/keycodes/keyboard_codes.h"
32 namespace input_method {
35 const char nacl_mozc_us_id[] =
36 "_comp_ime_fpfbhcjppmaeaijcidgiibchfbnhbeljnacl_mozc_us";
37 const char nacl_mozc_jp_id[] =
38 "_comp_ime_fpfbhcjppmaeaijcidgiibchfbnhbeljnacl_mozc_jp";
40 // Returns true if |descriptors| contain |target|.
41 bool Contain(const InputMethodDescriptors& descriptors,
42 const InputMethodDescriptor& target) {
43 for (size_t i = 0; i < descriptors.size(); ++i) {
44 if (descriptors[i].id() == target.id())
50 class InputMethodManagerImplTest : public testing::Test {
52 InputMethodManagerImplTest()
55 candidate_window_controller_(NULL),
58 virtual ~InputMethodManagerImplTest() {}
60 virtual void SetUp() OVERRIDE {
61 mock_ibus_daemon_controller_ = new chromeos::MockIBusDaemonController();
62 chromeos::IBusDaemonController::InitializeForTesting(
63 mock_ibus_daemon_controller_);
64 fake_dbus_thread_manager_ =
65 new chromeos::FakeDBusThreadManager();
66 chromeos::DBusThreadManager::InitializeForTesting(
67 fake_dbus_thread_manager_);
68 delegate_ = new FakeInputMethodDelegate();
69 manager_.reset(new InputMethodManagerImpl(
70 scoped_ptr<InputMethodDelegate>(delegate_)));
71 controller_ = new MockIBusController;
72 manager_->SetIBusControllerForTesting(controller_);
73 candidate_window_controller_ = new MockCandidateWindowController;
74 manager_->SetCandidateWindowControllerForTesting(
75 candidate_window_controller_);
76 xkeyboard_ = new MockXKeyboard;
77 manager_->SetXKeyboardForTesting(xkeyboard_);
78 mock_engine_handler_.reset(new MockIMEEngineHandler());
79 IBusBridge::Initialize();
80 IBusBridge::Get()->SetEngineHandler(mock_engine_handler_.get());
84 ComponentExtensionIME ext1;
85 ext1.id = "fpfbhcjppmaeaijcidgiibchfbnhbelj";
86 ext1.description = "ext1_description";
87 ext1.path = base::FilePath("ext1_file_path");
89 ComponentExtensionEngine ext1_engine1;
90 ext1_engine1.engine_id = "nacl_mozc_us";
91 ext1_engine1.display_name = "ext1_engine_1_display_name";
92 ext1_engine1.language_codes.push_back("ja");
93 ext1_engine1.layouts.push_back("us");
94 ext1.engines.push_back(ext1_engine1);
96 ComponentExtensionEngine ext1_engine2;
97 ext1_engine2.engine_id = "nacl_mozc_jp";
98 ext1_engine2.display_name = "ext1_engine_1_display_name";
99 ext1_engine2.language_codes.push_back("ja");
100 ext1_engine2.layouts.push_back("jp");
101 ext1.engines.push_back(ext1_engine2);
103 ime_list_.push_back(ext1);
105 ComponentExtensionIME ext2;
106 ext2.id = "nmblnjkfdkabgdofidlkienfnnbjhnab";
107 ext2.description = "ext2_description";
108 ext2.path = base::FilePath("ext2_file_path");
110 ComponentExtensionEngine ext2_engine1;
111 ext2_engine1.engine_id = "ext2_engine1_engine_id";
112 ext2_engine1.display_name = "ext2_engine_1_display_name";
113 ext2_engine1.language_codes.push_back("en");
114 ext2_engine1.layouts.push_back("us");
115 ext2.engines.push_back(ext2_engine1);
117 ComponentExtensionEngine ext2_engine2;
118 ext2_engine2.engine_id = "ext2_engine2_engine_id";
119 ext2_engine2.display_name = "ext2_engine_2_display_name";
120 ext2_engine2.language_codes.push_back("en");
121 ext2_engine2.layouts.push_back("us(dvorak)");
122 ext2.engines.push_back(ext2_engine2);
124 ime_list_.push_back(ext2);
126 mock_ibus_daemon_controller_->EmulateConnect();
129 virtual void TearDown() OVERRIDE {
130 mock_ibus_daemon_controller_->EmulateDisconnect();
133 candidate_window_controller_ = NULL;
136 IBusBridge::Get()->SetEngineHandler(NULL);
137 IBusBridge::Shutdown();
138 chromeos::DBusThreadManager::Shutdown();
139 chromeos::IBusDaemonController::Shutdown();
143 // Helper function to initialize component extension stuff for testing.
144 void InitComponentExtension() {
145 mock_delegate_ = new MockComponentExtIMEManagerDelegate();
146 mock_delegate_->set_ime_list(ime_list_);
147 scoped_ptr<ComponentExtensionIMEManagerDelegate> delegate(mock_delegate_);
148 manager_->InitializeComponentExtensionForTesting(delegate.Pass());
151 // Helper function to initialize IBus bus connection for testing. Do not use
152 // ibus related mocks before calling this function.
154 fake_dbus_thread_manager_->InitIBusBus("dummy address",
155 base::Bind(&base::DoNothing));
156 mock_ibus_client_ = fake_dbus_thread_manager_->mock_ibus_client();
157 mock_ibus_daemon_controller_->EmulateConnect();
160 scoped_ptr<InputMethodManagerImpl> manager_;
161 FakeInputMethodDelegate* delegate_;
162 MockIBusController* controller_;
163 MockCandidateWindowController* candidate_window_controller_;
164 MockIBusDaemonController* mock_ibus_daemon_controller_;
165 scoped_ptr<MockIMEEngineHandler> mock_engine_handler_;
166 MockIBusClient* mock_ibus_client_;
167 FakeDBusThreadManager* fake_dbus_thread_manager_;
168 MockXKeyboard* xkeyboard_;
169 base::MessageLoop message_loop_;
170 MockComponentExtIMEManagerDelegate* mock_delegate_;
171 std::vector<ComponentExtensionIME> ime_list_;
174 DISALLOW_COPY_AND_ASSIGN(InputMethodManagerImplTest);
177 class TestableComponentExtensionIMEManager
178 : public ComponentExtensionIMEManager {
180 using ComponentExtensionIMEManager::GetComponentExtensionIMEId;
183 class TestObserver : public InputMethodManager::Observer {
186 : input_method_changed_count_(0),
187 input_method_property_changed_count_(0),
188 last_show_message_(false) {
190 virtual ~TestObserver() {}
192 virtual void InputMethodChanged(InputMethodManager* manager,
193 bool show_message) OVERRIDE {
194 ++input_method_changed_count_;
195 last_show_message_ = show_message;
197 virtual void InputMethodPropertyChanged(
198 InputMethodManager* manager) OVERRIDE {
199 ++input_method_property_changed_count_;
202 int input_method_changed_count_;
203 int input_method_property_changed_count_;
204 bool last_show_message_;
207 DISALLOW_COPY_AND_ASSIGN(TestObserver);
210 class TestCandidateWindowObserver
211 : public InputMethodManager::CandidateWindowObserver {
213 TestCandidateWindowObserver()
214 : candidate_window_opened_count_(0),
215 candidate_window_closed_count_(0) {
217 virtual ~TestCandidateWindowObserver() {}
219 virtual void CandidateWindowOpened(InputMethodManager* manager) OVERRIDE {
220 ++candidate_window_opened_count_;
222 virtual void CandidateWindowClosed(InputMethodManager* manager) OVERRIDE {
223 ++candidate_window_closed_count_;
226 int candidate_window_opened_count_;
227 int candidate_window_closed_count_;
230 DISALLOW_COPY_AND_ASSIGN(TestCandidateWindowObserver);
235 TEST_F(InputMethodManagerImplTest, TestGetXKeyboard) {
236 EXPECT_TRUE(manager_->GetXKeyboard());
237 EXPECT_EQ(xkeyboard_, manager_->GetXKeyboard());
240 TEST_F(InputMethodManagerImplTest, TestCandidateWindowObserver) {
241 TestCandidateWindowObserver observer;
242 candidate_window_controller_->NotifyCandidateWindowOpened(); // nop
243 candidate_window_controller_->NotifyCandidateWindowClosed(); // nop
244 manager_->AddCandidateWindowObserver(&observer);
245 candidate_window_controller_->NotifyCandidateWindowOpened();
246 EXPECT_EQ(1, observer.candidate_window_opened_count_);
247 candidate_window_controller_->NotifyCandidateWindowClosed();
248 EXPECT_EQ(1, observer.candidate_window_closed_count_);
249 candidate_window_controller_->NotifyCandidateWindowOpened();
250 EXPECT_EQ(2, observer.candidate_window_opened_count_);
251 candidate_window_controller_->NotifyCandidateWindowClosed();
252 EXPECT_EQ(2, observer.candidate_window_closed_count_);
253 manager_->RemoveCandidateWindowObserver(&observer);
256 TEST_F(InputMethodManagerImplTest, TestObserver) {
257 // For http://crbug.com/19655#c11 - (3). browser_state_monitor_unittest.cc is
258 // also for the scenario.
259 TestObserver observer;
260 InitComponentExtension();
262 manager_->AddObserver(&observer);
263 EXPECT_EQ(0, observer.input_method_changed_count_);
264 manager_->EnableLayouts("en-US", "xkb:us::eng");
265 EXPECT_EQ(1, observer.input_method_changed_count_);
266 EXPECT_EQ(1, observer.input_method_property_changed_count_);
267 manager_->ChangeInputMethod("xkb:us:dvorak:eng");
268 EXPECT_FALSE(observer.last_show_message_);
269 EXPECT_EQ(2, observer.input_method_changed_count_);
270 EXPECT_EQ(2, observer.input_method_property_changed_count_);
271 manager_->ChangeInputMethod("xkb:us:dvorak:eng");
272 EXPECT_FALSE(observer.last_show_message_);
273 // The observer is always notified even when the same input method ID is
274 // passed to ChangeInputMethod() more than twice.
275 EXPECT_EQ(3, observer.input_method_changed_count_);
276 EXPECT_EQ(3, observer.input_method_property_changed_count_);
278 controller_->NotifyPropertyChangedForTesting();
279 EXPECT_EQ(4, observer.input_method_property_changed_count_);
280 controller_->NotifyPropertyChangedForTesting();
281 EXPECT_EQ(5, observer.input_method_property_changed_count_);
282 manager_->RemoveObserver(&observer);
285 TEST_F(InputMethodManagerImplTest, TestGetSupportedInputMethods) {
286 InitComponentExtension();
288 scoped_ptr<InputMethodDescriptors> methods(
289 manager_->GetSupportedInputMethods());
290 ASSERT_TRUE(methods.get());
291 // Try to find random 4-5 layuts and IMEs to make sure the returned list is
293 const InputMethodDescriptor* id_to_find =
294 manager_->GetInputMethodUtil()->GetInputMethodDescriptorFromId(
296 id_to_find = manager_->GetInputMethodUtil()->GetInputMethodDescriptorFromId(
298 EXPECT_TRUE(Contain(*methods.get(), *id_to_find));
299 id_to_find = manager_->GetInputMethodUtil()->GetInputMethodDescriptorFromId(
300 "xkb:us:dvorak:eng");
301 EXPECT_TRUE(Contain(*methods.get(), *id_to_find));
302 id_to_find = manager_->GetInputMethodUtil()->GetInputMethodDescriptorFromId(
304 EXPECT_TRUE(Contain(*methods.get(), *id_to_find));
307 TEST_F(InputMethodManagerImplTest, TestEnableLayouts) {
308 // Currently 5 keyboard layouts are supported for en-US, and 1 for ja. See
309 // ibus_input_method.txt.
310 InitComponentExtension();
312 manager_->EnableLayouts("en-US", "");
313 EXPECT_EQ(5U, manager_->GetNumActiveInputMethods());
314 for (size_t i = 0; i < manager_->GetActiveInputMethodIds().size(); ++i)
315 LOG(ERROR) << manager_->GetActiveInputMethodIds().at(i);
316 // For http://crbug.com/19655#c11 - (2)
317 EXPECT_EQ(0, mock_ibus_daemon_controller_->start_count());
319 // For http://crbug.com/19655#c11 - (5)
320 // The hardware keyboard layout "xkb:us::eng" is always active, hence 2U.
321 manager_->EnableLayouts("ja", ""); // Japanese
322 EXPECT_EQ(2U, manager_->GetNumActiveInputMethods());
323 EXPECT_EQ(0, mock_ibus_daemon_controller_->start_count());
326 TEST_F(InputMethodManagerImplTest, TestEnableLayoutsNonUsHardwareKeyboard) {
327 // The physical layout is French.
328 delegate_->set_hardware_keyboard_layout("xkb:fr::fra");
329 manager_->EnableLayouts("en-US", "");
330 EXPECT_EQ(6U, manager_->GetNumActiveInputMethods()); // 5 + French
331 // The physical layout is Japanese.
332 delegate_->set_hardware_keyboard_layout("xkb:jp::jpn");
333 manager_->EnableLayouts("ja", "");
334 // "xkb:us::eng" is not needed, hence 1.
335 EXPECT_EQ(1U, manager_->GetNumActiveInputMethods());
338 TEST_F(InputMethodManagerImplTest, TestActiveInputMethods) {
339 manager_->EnableLayouts("ja", ""); // Japanese
340 EXPECT_EQ(2U, manager_->GetNumActiveInputMethods());
341 scoped_ptr<InputMethodDescriptors> methods(
342 manager_->GetActiveInputMethods());
343 ASSERT_TRUE(methods.get());
344 EXPECT_EQ(2U, methods->size());
345 const InputMethodDescriptor* id_to_find =
346 manager_->GetInputMethodUtil()->GetInputMethodDescriptorFromId(
348 EXPECT_TRUE(Contain(*methods.get(), *id_to_find));
349 id_to_find = manager_->GetInputMethodUtil()->GetInputMethodDescriptorFromId(
351 EXPECT_TRUE(Contain(*methods.get(), *id_to_find));
354 TEST_F(InputMethodManagerImplTest, TestEnableTwoLayouts) {
355 // For http://crbug.com/19655#c11 - (8), step 6.
356 TestObserver observer;
357 manager_->AddObserver(&observer);
358 InitComponentExtension();
360 manager_->SetState(InputMethodManager::STATE_BROWSER_SCREEN);
361 std::vector<std::string> ids;
362 ids.push_back("xkb:us:dvorak:eng");
363 ids.push_back("xkb:us:colemak:eng");
364 EXPECT_TRUE(manager_->EnableInputMethods(ids));
365 EXPECT_EQ(2U, manager_->GetNumActiveInputMethods());
366 // Since all the IDs added avobe are keyboard layouts, Start() should not be
368 EXPECT_EQ(0, mock_ibus_daemon_controller_->start_count());
369 EXPECT_EQ(1, observer.input_method_changed_count_);
370 EXPECT_EQ(ids[0], manager_->GetCurrentInputMethod().id());
371 EXPECT_EQ("us(dvorak)", xkeyboard_->last_layout_);
373 ids.erase(ids.begin());
374 EXPECT_TRUE(manager_->EnableInputMethods(ids));
375 EXPECT_EQ(1U, manager_->GetNumActiveInputMethods());
376 EXPECT_EQ(2, observer.input_method_changed_count_);
377 EXPECT_EQ(ids[0], // colemak
378 manager_->GetCurrentInputMethod().id());
379 EXPECT_EQ("us(colemak)", xkeyboard_->last_layout_);
380 manager_->RemoveObserver(&observer);
383 TEST_F(InputMethodManagerImplTest, TestEnableThreeLayouts) {
384 // For http://crbug.com/19655#c11 - (9).
385 TestObserver observer;
386 manager_->AddObserver(&observer);
387 InitComponentExtension();
389 manager_->SetState(InputMethodManager::STATE_BROWSER_SCREEN);
390 std::vector<std::string> ids;
391 ids.push_back("xkb:us::eng");
392 ids.push_back("xkb:us:dvorak:eng");
393 ids.push_back("xkb:us:colemak:eng");
394 EXPECT_TRUE(manager_->EnableInputMethods(ids));
395 EXPECT_EQ(3U, manager_->GetNumActiveInputMethods());
396 EXPECT_EQ(1, observer.input_method_changed_count_);
397 EXPECT_EQ(ids[0], manager_->GetCurrentInputMethod().id());
398 EXPECT_EQ("us", xkeyboard_->last_layout_);
400 manager_->SwitchToNextInputMethod();
401 EXPECT_EQ(2, observer.input_method_changed_count_);
402 EXPECT_EQ(ids[1], manager_->GetCurrentInputMethod().id());
403 EXPECT_EQ("us(dvorak)", xkeyboard_->last_layout_);
405 ids.erase(ids.begin() + 1);
406 EXPECT_TRUE(manager_->EnableInputMethods(ids));
407 EXPECT_EQ(2U, manager_->GetNumActiveInputMethods());
408 EXPECT_EQ(3, observer.input_method_changed_count_);
409 EXPECT_EQ(ids[0], // US Qwerty
410 manager_->GetCurrentInputMethod().id());
411 EXPECT_EQ("us", xkeyboard_->last_layout_);
412 manager_->RemoveObserver(&observer);
415 TEST_F(InputMethodManagerImplTest, TestEnableLayoutAndIme) {
416 // For http://crbug.com/19655#c11 - (10).
417 TestObserver observer;
418 manager_->AddObserver(&observer);
419 InitComponentExtension();
421 manager_->SetState(InputMethodManager::STATE_BROWSER_SCREEN);
422 std::vector<std::string> ids;
423 ids.push_back("xkb:us:dvorak:eng");
424 ids.push_back(nacl_mozc_us_id);
425 EXPECT_TRUE(manager_->EnableInputMethods(ids));
426 EXPECT_EQ(1, mock_ibus_daemon_controller_->start_count());
427 EXPECT_EQ(1, observer.input_method_changed_count_);
428 EXPECT_EQ(ids[0], manager_->GetCurrentInputMethod().id());
429 EXPECT_EQ("us(dvorak)", xkeyboard_->last_layout_);
431 manager_->SwitchToNextInputMethod();
432 EXPECT_EQ(2, observer.input_method_changed_count_);
433 EXPECT_EQ(ids[1], manager_->GetCurrentInputMethod().id());
434 EXPECT_EQ("us", xkeyboard_->last_layout_);
436 ids.erase(ids.begin() + 1);
437 EXPECT_TRUE(manager_->EnableInputMethods(ids));
438 EXPECT_EQ(1U, manager_->GetNumActiveInputMethods());
439 EXPECT_EQ(ids[0], manager_->GetCurrentInputMethod().id());
440 EXPECT_EQ("us(dvorak)", xkeyboard_->last_layout_);
441 // Currently, to work around a crash issue at crosbug.com/27051,
442 // controller_->Stop(); is NOT called when all IMEs are disabled
444 EXPECT_EQ(0, mock_ibus_daemon_controller_->stop_count());
446 manager_->SetState(InputMethodManager::STATE_TERMINATING);
447 EXPECT_EQ(0, mock_ibus_daemon_controller_->stop_count());
448 manager_->RemoveObserver(&observer);
451 TEST_F(InputMethodManagerImplTest, TestEnableLayoutAndIme2) {
452 // For http://crbug.com/19655#c11 - (11).
453 TestObserver observer;
454 manager_->AddObserver(&observer);
455 InitComponentExtension();
457 manager_->SetState(InputMethodManager::STATE_BROWSER_SCREEN);
458 std::vector<std::string> ids;
459 ids.push_back("xkb:us:dvorak:eng");
460 ids.push_back(nacl_mozc_us_id);
461 EXPECT_TRUE(manager_->EnableInputMethods(ids));
462 EXPECT_EQ(1, mock_ibus_daemon_controller_->start_count());
463 EXPECT_EQ(1, observer.input_method_changed_count_);
464 EXPECT_EQ(ids[0], manager_->GetCurrentInputMethod().id());
465 EXPECT_EQ("us(dvorak)", xkeyboard_->last_layout_);
468 ids.erase(ids.begin());
469 EXPECT_TRUE(manager_->EnableInputMethods(ids));
470 EXPECT_EQ(1U, manager_->GetNumActiveInputMethods());
471 EXPECT_EQ(ids[0], // Mozc
472 manager_->GetCurrentInputMethod().id());
473 EXPECT_EQ("us", xkeyboard_->last_layout_);
474 manager_->RemoveObserver(&observer);
477 TEST_F(InputMethodManagerImplTest, TestEnableImes) {
478 TestObserver observer;
479 manager_->AddObserver(&observer);
480 InitComponentExtension();
482 manager_->SetState(InputMethodManager::STATE_BROWSER_SCREEN);
483 std::vector<std::string> ids;
484 ids.push_back("_comp_ime_nmblnjkfdkabgdofidlkienfnnbjhnabext2_engine1_engine_id");
485 ids.push_back("mozc-dv");
486 EXPECT_TRUE(manager_->EnableInputMethods(ids));
487 EXPECT_EQ(1, mock_ibus_daemon_controller_->start_count());
488 EXPECT_EQ(1, observer.input_method_changed_count_);
489 EXPECT_EQ(ids[0], manager_->GetCurrentInputMethod().id());
490 EXPECT_EQ("us", xkeyboard_->last_layout_);
491 manager_->RemoveObserver(&observer);
494 TEST_F(InputMethodManagerImplTest, TestEnableUnknownIds) {
495 TestObserver observer;
496 manager_->AddObserver(&observer);
497 manager_->SetState(InputMethodManager::STATE_BROWSER_SCREEN);
498 std::vector<std::string> ids;
499 ids.push_back("xkb:tl::tlh"); // Klingon, which is not supported.
500 ids.push_back("unknown-super-cool-ime");
501 EXPECT_FALSE(manager_->EnableInputMethods(ids));
503 // TODO(yusukes): Should we fall back to the hardware keyboard layout in this
505 EXPECT_EQ(0, observer.input_method_changed_count_);
507 manager_->RemoveObserver(&observer);
510 TEST_F(InputMethodManagerImplTest, TestEnableLayoutsThenLock) {
511 // For http://crbug.com/19655#c11 - (14).
512 TestObserver observer;
513 manager_->AddObserver(&observer);
514 InitComponentExtension();
516 manager_->SetState(InputMethodManager::STATE_BROWSER_SCREEN);
517 std::vector<std::string> ids;
518 ids.push_back("xkb:us::eng");
519 ids.push_back("xkb:us:dvorak:eng");
520 EXPECT_TRUE(manager_->EnableInputMethods(ids));
521 EXPECT_EQ(2U, manager_->GetNumActiveInputMethods());
522 EXPECT_EQ(1, observer.input_method_changed_count_);
523 EXPECT_EQ(ids[0], manager_->GetCurrentInputMethod().id());
524 EXPECT_EQ("us", xkeyboard_->last_layout_);
527 manager_->SwitchToNextInputMethod();
528 EXPECT_EQ(2, observer.input_method_changed_count_);
529 EXPECT_EQ(ids[1], manager_->GetCurrentInputMethod().id());
530 EXPECT_EQ("us(dvorak)", xkeyboard_->last_layout_);
533 manager_->SetState(InputMethodManager::STATE_LOCK_SCREEN);
534 EXPECT_EQ(2U, manager_->GetNumActiveInputMethods());
535 EXPECT_EQ(ids[1], // still Dvorak
536 manager_->GetCurrentInputMethod().id());
537 EXPECT_EQ("us(dvorak)", xkeyboard_->last_layout_);
538 // Switch back to Qwerty.
539 manager_->SwitchToNextInputMethod();
540 EXPECT_EQ(ids[0], manager_->GetCurrentInputMethod().id());
541 EXPECT_EQ("us", xkeyboard_->last_layout_);
543 // Unlock screen. The original state, Dvorak, is restored.
544 manager_->SetState(InputMethodManager::STATE_BROWSER_SCREEN);
545 EXPECT_EQ(2U, manager_->GetNumActiveInputMethods());
546 EXPECT_EQ(ids[1], manager_->GetCurrentInputMethod().id());
547 EXPECT_EQ("us(dvorak)", xkeyboard_->last_layout_);
549 manager_->RemoveObserver(&observer);
552 TEST_F(InputMethodManagerImplTest, SwithchInputMethodTest) {
553 // For http://crbug.com/19655#c11 - (15).
554 TestObserver observer;
555 manager_->AddObserver(&observer);
556 InitComponentExtension();
558 manager_->SetState(InputMethodManager::STATE_BROWSER_SCREEN);
559 std::vector<std::string> ids;
560 ids.push_back("xkb:us:dvorak:eng");
561 ids.push_back("_comp_ime_nmblnjkfdkabgdofidlkienfnnbjhnabext2_engine2_engine_id");
562 ids.push_back("_comp_ime_nmblnjkfdkabgdofidlkienfnnbjhnabext2_engine1_engine_id");
563 EXPECT_TRUE(manager_->EnableInputMethods(ids));
564 EXPECT_EQ(3U, manager_->GetNumActiveInputMethods());
565 EXPECT_EQ(1, observer.input_method_changed_count_);
566 EXPECT_EQ(ids[0], manager_->GetCurrentInputMethod().id());
567 EXPECT_EQ("us(dvorak)", xkeyboard_->last_layout_);
570 manager_->SwitchToNextInputMethod();
571 EXPECT_EQ(2, observer.input_method_changed_count_);
572 EXPECT_EQ(ids[1], manager_->GetCurrentInputMethod().id());
573 EXPECT_EQ("us(dvorak)", xkeyboard_->last_layout_);
576 manager_->SetState(InputMethodManager::STATE_LOCK_SCREEN);
577 EXPECT_EQ(2U, manager_->GetNumActiveInputMethods()); // Qwerty+Dvorak.
578 EXPECT_EQ("xkb:us:dvorak:eng",
579 manager_->GetCurrentInputMethod().id());
580 EXPECT_EQ("us(dvorak)", xkeyboard_->last_layout_);
581 // controller_->Stop() should never be called when the screen is locked even
582 // after crosbug.com/27051 is fixed.
583 EXPECT_EQ(0, mock_ibus_daemon_controller_->stop_count());
584 manager_->SwitchToNextInputMethod();
585 EXPECT_EQ("xkb:us::eng", // The hardware keyboard layout.
586 manager_->GetCurrentInputMethod().id());
587 EXPECT_EQ("us", xkeyboard_->last_layout_);
589 // Unlock screen. The original state, pinyin-dv, is restored.
590 manager_->SetState(InputMethodManager::STATE_BROWSER_SCREEN);
591 EXPECT_EQ(3U, manager_->GetNumActiveInputMethods()); // Dvorak and 2 IMEs.
592 EXPECT_EQ(ids[1], manager_->GetCurrentInputMethod().id());
593 EXPECT_EQ("us(dvorak)", xkeyboard_->last_layout_);
595 manager_->RemoveObserver(&observer);
598 TEST_F(InputMethodManagerImplTest, TestXkbSetting) {
599 // For http://crbug.com/19655#c11 - (8), step 7-11.
600 InitComponentExtension();
602 manager_->SetState(InputMethodManager::STATE_BROWSER_SCREEN);
603 std::vector<std::string> ids;
604 ids.push_back("xkb:us:dvorak:eng");
605 ids.push_back("xkb:us:colemak:eng");
606 ids.push_back(nacl_mozc_jp_id);
607 ids.push_back(nacl_mozc_us_id);
608 EXPECT_TRUE(manager_->EnableInputMethods(ids));
609 EXPECT_EQ(4U, manager_->GetNumActiveInputMethods());
610 EXPECT_EQ(1, xkeyboard_->set_current_keyboard_layout_by_name_count_);
611 // See input_methods.txt for an expected XKB layout name.
612 EXPECT_EQ("us(dvorak)", xkeyboard_->last_layout_);
613 manager_->SwitchToNextInputMethod();
614 EXPECT_EQ(2, xkeyboard_->set_current_keyboard_layout_by_name_count_);
615 EXPECT_EQ("us(colemak)", xkeyboard_->last_layout_);
616 manager_->SwitchToNextInputMethod();
617 EXPECT_EQ(3, xkeyboard_->set_current_keyboard_layout_by_name_count_);
618 EXPECT_EQ("jp", xkeyboard_->last_layout_);
619 manager_->SwitchToNextInputMethod();
620 EXPECT_EQ(4, xkeyboard_->set_current_keyboard_layout_by_name_count_);
621 EXPECT_EQ("us", xkeyboard_->last_layout_);
622 manager_->SwitchToNextInputMethod();
623 EXPECT_EQ(5, xkeyboard_->set_current_keyboard_layout_by_name_count_);
624 EXPECT_EQ("us(dvorak)", xkeyboard_->last_layout_);
626 ids.erase(ids.begin());
627 EXPECT_TRUE(manager_->EnableInputMethods(ids));
628 EXPECT_EQ(3U, manager_->GetNumActiveInputMethods());
629 EXPECT_EQ(6, xkeyboard_->set_current_keyboard_layout_by_name_count_);
630 EXPECT_EQ("us(colemak)", xkeyboard_->last_layout_);
633 TEST_F(InputMethodManagerImplTest, TestActivateInputMethodProperty) {
634 manager_->ActivateInputMethodProperty("key");
635 EXPECT_EQ(1, controller_->activate_input_method_property_count_);
636 EXPECT_EQ("key", controller_->activate_input_method_property_key_);
637 manager_->ActivateInputMethodProperty("key2");
638 EXPECT_EQ(2, controller_->activate_input_method_property_count_);
639 EXPECT_EQ("key2", controller_->activate_input_method_property_key_);
642 TEST_F(InputMethodManagerImplTest, TestGetCurrentInputMethodProperties) {
643 InitComponentExtension();
645 EXPECT_TRUE(manager_->GetCurrentInputMethodProperties().empty());
647 manager_->SetState(InputMethodManager::STATE_BROWSER_SCREEN);
648 std::vector<std::string> ids;
649 ids.push_back("xkb:us::eng");
650 ids.push_back(nacl_mozc_us_id);
651 EXPECT_TRUE(manager_->EnableInputMethods(ids));
652 EXPECT_EQ(2U, manager_->GetNumActiveInputMethods());
653 EXPECT_TRUE(manager_->GetCurrentInputMethodProperties().empty());
654 manager_->ChangeInputMethod(nacl_mozc_us_id);
656 InputMethodPropertyList current_property_list;
657 current_property_list.push_back(InputMethodProperty("key",
661 controller_->SetCurrentPropertiesForTesting(current_property_list);
662 controller_->NotifyPropertyChangedForTesting();
664 ASSERT_EQ(1U, manager_->GetCurrentInputMethodProperties().size());
665 EXPECT_EQ("key", manager_->GetCurrentInputMethodProperties().at(0).key);
667 manager_->ChangeInputMethod("xkb:us::eng");
668 EXPECT_TRUE(manager_->GetCurrentInputMethodProperties().empty());
670 // Delayed asynchronous property update signal from the Mozc IME.
671 controller_->NotifyPropertyChangedForTesting();
672 // When XKB layout is in use, GetCurrentInputMethodProperties() should always
673 // return an empty list.
674 EXPECT_TRUE(manager_->GetCurrentInputMethodProperties().empty());
677 TEST_F(InputMethodManagerImplTest, TestGetCurrentInputMethodPropertiesTwoImes) {
678 InitComponentExtension();
680 EXPECT_TRUE(manager_->GetCurrentInputMethodProperties().empty());
682 manager_->SetState(InputMethodManager::STATE_BROWSER_SCREEN);
683 std::vector<std::string> ids;
684 ids.push_back(nacl_mozc_us_id); // Japanese
685 ids.push_back("_comp_ime_nmblnjkfdkabgdofidlkienfnnbjhnabext2_engine1_engine_id"); // T-Chinese
686 EXPECT_TRUE(manager_->EnableInputMethods(ids));
687 EXPECT_EQ(2U, manager_->GetNumActiveInputMethods());
688 EXPECT_TRUE(manager_->GetCurrentInputMethodProperties().empty());
690 InputMethodPropertyList current_property_list;
691 current_property_list.push_back(InputMethodProperty("key-mozc",
695 controller_->SetCurrentPropertiesForTesting(current_property_list);
696 controller_->NotifyPropertyChangedForTesting();
698 ASSERT_EQ(1U, manager_->GetCurrentInputMethodProperties().size());
699 EXPECT_EQ("key-mozc", manager_->GetCurrentInputMethodProperties().at(0).key);
701 manager_->ChangeInputMethod("_comp_ime_nmblnjkfdkabgdofidlkienfnnbjhnabext2_engine1_engine_id");
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 controller_->SetCurrentPropertiesForTesting(current_property_list);
712 controller_->NotifyPropertyChangedForTesting();
713 ASSERT_EQ(1U, manager_->GetCurrentInputMethodProperties().size());
714 EXPECT_EQ("key-chewing",
715 manager_->GetCurrentInputMethodProperties().at(0).key);
718 TEST_F(InputMethodManagerImplTest, TestNextInputMethod) {
719 TestObserver observer;
720 manager_->AddObserver(&observer);
721 InitComponentExtension();
723 // For http://crbug.com/19655#c11 - (1)
724 manager_->EnableLayouts("en-US", "xkb:us::eng");
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();
758 ui::Accelerator keydown_accelerator(ui::VKEY_SPACE, ui::EF_CONTROL_DOWN);
759 keydown_accelerator.set_type(ui::ET_KEY_PRESSED);
760 ui::Accelerator keyup_accelerator(ui::VKEY_SPACE, ui::EF_CONTROL_DOWN);
761 keyup_accelerator.set_type(ui::ET_KEY_RELEASED);
763 manager_->EnableLayouts("en-US", "xkb:us::eng");
764 EXPECT_EQ(5U, manager_->GetNumActiveInputMethods());
765 EXPECT_EQ("xkb:us::eng", manager_->GetCurrentInputMethod().id());
766 EXPECT_EQ("us", xkeyboard_->last_layout_);
767 EXPECT_TRUE(manager_->SwitchToNextInputMethod());
768 EXPECT_TRUE(observer.last_show_message_);
769 EXPECT_EQ("xkb:us:intl:eng", manager_->GetCurrentInputMethod().id());
770 EXPECT_EQ("us(intl)", xkeyboard_->last_layout_);
771 EXPECT_TRUE(manager_->SwitchToPreviousInputMethod(keydown_accelerator));
772 EXPECT_TRUE(manager_->SwitchToPreviousInputMethod(keyup_accelerator));
773 EXPECT_TRUE(observer.last_show_message_);
774 EXPECT_EQ("xkb:us::eng", manager_->GetCurrentInputMethod().id());
775 EXPECT_EQ("us", xkeyboard_->last_layout_);
776 EXPECT_TRUE(manager_->SwitchToPreviousInputMethod(keydown_accelerator));
777 EXPECT_TRUE(manager_->SwitchToPreviousInputMethod(keyup_accelerator));
778 EXPECT_TRUE(observer.last_show_message_);
779 EXPECT_EQ("xkb:us:intl:eng", manager_->GetCurrentInputMethod().id());
780 EXPECT_EQ("us(intl)", xkeyboard_->last_layout_);
781 EXPECT_TRUE(manager_->SwitchToPreviousInputMethod(keydown_accelerator));
782 EXPECT_TRUE(manager_->SwitchToPreviousInputMethod(keyup_accelerator));
783 EXPECT_TRUE(observer.last_show_message_);
784 EXPECT_EQ("xkb:us::eng", manager_->GetCurrentInputMethod().id());
785 EXPECT_EQ("us", xkeyboard_->last_layout_);
786 EXPECT_TRUE(manager_->SwitchToNextInputMethod());
787 EXPECT_TRUE(observer.last_show_message_);
788 EXPECT_EQ("xkb:us:intl:eng", manager_->GetCurrentInputMethod().id());
789 EXPECT_EQ("us(intl)", xkeyboard_->last_layout_);
790 EXPECT_TRUE(manager_->SwitchToNextInputMethod());
791 EXPECT_TRUE(observer.last_show_message_);
792 EXPECT_EQ("xkb:us:altgr-intl:eng", manager_->GetCurrentInputMethod().id());
793 EXPECT_EQ("us(altgr-intl)", xkeyboard_->last_layout_);
794 EXPECT_TRUE(manager_->SwitchToPreviousInputMethod(keydown_accelerator));
795 EXPECT_TRUE(manager_->SwitchToPreviousInputMethod(keyup_accelerator));
796 EXPECT_TRUE(observer.last_show_message_);
797 EXPECT_EQ("xkb:us:intl:eng", manager_->GetCurrentInputMethod().id());
798 EXPECT_EQ("us(intl)", xkeyboard_->last_layout_);
799 EXPECT_TRUE(manager_->SwitchToPreviousInputMethod(keydown_accelerator));
800 EXPECT_TRUE(manager_->SwitchToPreviousInputMethod(keyup_accelerator));
801 EXPECT_TRUE(observer.last_show_message_);
802 EXPECT_EQ("xkb:us:altgr-intl:eng", manager_->GetCurrentInputMethod().id());
803 EXPECT_EQ("us(altgr-intl)", xkeyboard_->last_layout_);
805 manager_->RemoveObserver(&observer);
808 TEST_F(InputMethodManagerImplTest,
809 TestSwitchToPreviousInputMethodForOneActiveInputMethod) {
810 TestObserver observer;
811 manager_->AddObserver(&observer);
812 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_->EnableInputMethods(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();
838 manager_->EnableLayouts("en-US", "xkb:us::eng");
839 EXPECT_EQ(5U, manager_->GetNumActiveInputMethods());
840 EXPECT_EQ("xkb:us::eng", manager_->GetCurrentInputMethod().id());
841 EXPECT_EQ("us", xkeyboard_->last_layout_);
843 // Henkan, Muhenkan, ZenkakuHankaku should be ignored when no Japanese IMEs
844 // and keyboards are enabled.
845 EXPECT_FALSE(manager_->SwitchInputMethod(
846 ui::Accelerator(ui::VKEY_CONVERT, ui::EF_NONE)));
847 EXPECT_FALSE(observer.last_show_message_);
848 EXPECT_EQ("xkb:us::eng", manager_->GetCurrentInputMethod().id());
849 EXPECT_EQ("us", xkeyboard_->last_layout_);
850 EXPECT_FALSE(manager_->SwitchInputMethod(
851 ui::Accelerator(ui::VKEY_NONCONVERT, ui::EF_NONE)));
852 EXPECT_EQ("xkb:us::eng", manager_->GetCurrentInputMethod().id());
853 EXPECT_EQ("us", xkeyboard_->last_layout_);
854 EXPECT_FALSE(manager_->SwitchInputMethod(
855 ui::Accelerator(ui::VKEY_DBE_SBCSCHAR, ui::EF_NONE)));
856 EXPECT_EQ("xkb:us::eng", manager_->GetCurrentInputMethod().id());
857 EXPECT_EQ("us", xkeyboard_->last_layout_);
858 EXPECT_FALSE(manager_->SwitchInputMethod(
859 ui::Accelerator(ui::VKEY_DBE_DBCSCHAR, ui::EF_NONE)));
860 EXPECT_EQ("xkb:us::eng", manager_->GetCurrentInputMethod().id());
861 EXPECT_EQ("us", xkeyboard_->last_layout_);
863 manager_->RemoveObserver(&observer);
866 TEST_F(InputMethodManagerImplTest, TestSwitchInputMethodWithJpLayout) {
867 // Enable "xkb:jp::jpn" and press Muhenkan/ZenkakuHankaku.
868 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 manager_->EnableLayouts("ja", "xkb:us::eng");
877 EXPECT_EQ(2U, manager_->GetNumActiveInputMethods());
878 EXPECT_EQ("xkb:us::eng", manager_->GetCurrentInputMethod().id());
879 EXPECT_EQ("us", xkeyboard_->last_layout_);
880 EXPECT_TRUE(manager_->SwitchInputMethod(
881 ui::Accelerator(ui::VKEY_NONCONVERT, ui::EF_NONE)));
882 EXPECT_EQ("xkb:jp::jpn", manager_->GetCurrentInputMethod().id());
883 EXPECT_EQ("jp", xkeyboard_->last_layout_);
884 EXPECT_TRUE(manager_->SwitchToPreviousInputMethod(keydown_accelerator));
885 EXPECT_TRUE(manager_->SwitchToPreviousInputMethod(keyup_accelerator));
886 EXPECT_EQ("xkb:us::eng", manager_->GetCurrentInputMethod().id());
887 EXPECT_EQ("us", xkeyboard_->last_layout_);
888 EXPECT_TRUE(manager_->SwitchInputMethod(
889 ui::Accelerator(ui::VKEY_DBE_SBCSCHAR, ui::EF_NONE)));
890 EXPECT_EQ("xkb:jp::jpn", manager_->GetCurrentInputMethod().id());
891 EXPECT_EQ("jp", xkeyboard_->last_layout_);
892 EXPECT_TRUE(manager_->SwitchToPreviousInputMethod(keydown_accelerator));
893 EXPECT_TRUE(manager_->SwitchToPreviousInputMethod(keyup_accelerator));
894 EXPECT_EQ("xkb:us::eng", manager_->GetCurrentInputMethod().id());
895 EXPECT_EQ("us", xkeyboard_->last_layout_);
896 EXPECT_TRUE(manager_->SwitchInputMethod(
897 ui::Accelerator(ui::VKEY_DBE_DBCSCHAR, ui::EF_NONE)));
898 EXPECT_EQ("xkb:jp::jpn", manager_->GetCurrentInputMethod().id());
899 EXPECT_EQ("jp", xkeyboard_->last_layout_);
902 TEST_F(InputMethodManagerImplTest, TestSwitchInputMethodWithJpIme) {
903 InitComponentExtension();
905 manager_->SetState(InputMethodManager::STATE_BROWSER_SCREEN);
906 std::vector<std::string> ids;
907 ids.push_back("xkb:jp::jpn");
908 ids.push_back(nacl_mozc_jp_id);
909 EXPECT_TRUE(manager_->EnableInputMethods(ids));
910 EXPECT_EQ("xkb:jp::jpn", manager_->GetCurrentInputMethod().id());
911 EXPECT_EQ("jp", xkeyboard_->last_layout_);
912 EXPECT_TRUE(manager_->SwitchInputMethod(
913 ui::Accelerator(ui::VKEY_DBE_DBCSCHAR, ui::EF_NONE)));
914 EXPECT_EQ(nacl_mozc_jp_id, manager_->GetCurrentInputMethod().id());
915 EXPECT_EQ("jp", xkeyboard_->last_layout_);
916 EXPECT_TRUE(manager_->SwitchInputMethod(
917 ui::Accelerator(ui::VKEY_DBE_DBCSCHAR, ui::EF_NONE)));
918 EXPECT_EQ("xkb:jp::jpn", manager_->GetCurrentInputMethod().id());
919 EXPECT_EQ("jp", xkeyboard_->last_layout_);
920 EXPECT_TRUE(manager_->SwitchInputMethod(
921 ui::Accelerator(ui::VKEY_CONVERT, ui::EF_NONE)));
922 EXPECT_EQ(nacl_mozc_jp_id, manager_->GetCurrentInputMethod().id());
923 EXPECT_EQ("jp", xkeyboard_->last_layout_);
924 EXPECT_TRUE(manager_->SwitchInputMethod(
925 ui::Accelerator(ui::VKEY_CONVERT, ui::EF_NONE)));
926 EXPECT_EQ(nacl_mozc_jp_id, manager_->GetCurrentInputMethod().id());
927 EXPECT_EQ("jp", xkeyboard_->last_layout_);
928 EXPECT_TRUE(manager_->SwitchInputMethod(
929 ui::Accelerator(ui::VKEY_NONCONVERT, ui::EF_NONE)));
930 EXPECT_EQ("xkb:jp::jpn", manager_->GetCurrentInputMethod().id());
931 EXPECT_EQ("jp", xkeyboard_->last_layout_);
932 EXPECT_TRUE(manager_->SwitchInputMethod(
933 ui::Accelerator(ui::VKEY_NONCONVERT, ui::EF_NONE)));
934 EXPECT_EQ("xkb:jp::jpn", manager_->GetCurrentInputMethod().id());
935 EXPECT_EQ("jp", xkeyboard_->last_layout_);
938 ids.push_back("xkb:us:dvorak:eng");
939 EXPECT_TRUE(manager_->EnableInputMethods(ids));
940 EXPECT_EQ("xkb:jp::jpn", manager_->GetCurrentInputMethod().id());
941 EXPECT_EQ("jp", xkeyboard_->last_layout_);
942 EXPECT_TRUE(manager_->SwitchInputMethod(
943 ui::Accelerator(ui::VKEY_DBE_SBCSCHAR, ui::EF_NONE)));
944 EXPECT_EQ(nacl_mozc_jp_id, manager_->GetCurrentInputMethod().id());
945 EXPECT_EQ("jp", xkeyboard_->last_layout_);
946 EXPECT_TRUE(manager_->SwitchInputMethod(
947 ui::Accelerator(ui::VKEY_DBE_SBCSCHAR, ui::EF_NONE)));
948 EXPECT_EQ("xkb:jp::jpn", manager_->GetCurrentInputMethod().id());
949 EXPECT_EQ("jp", xkeyboard_->last_layout_);
952 TEST_F(InputMethodManagerImplTest, TestAddRemoveExtensionInputMethods) {
953 TestObserver observer;
954 manager_->AddObserver(&observer);
955 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_->EnableInputMethods(ids));
961 EXPECT_EQ(1U, manager_->GetNumActiveInputMethods());
962 EXPECT_EQ(0, mock_ibus_daemon_controller_->start_count());
963 EXPECT_EQ(1, observer.input_method_changed_count_);
965 manager_->GetCurrentInputMethod().id());
966 EXPECT_EQ("us(dvorak)", xkeyboard_->last_layout_);
968 // Add two Extension IMEs.
969 std::vector<std::string> layouts;
970 layouts.push_back("us");
971 std::vector<std::string> languages;
972 languages.push_back("en-US");
973 manager_->AddInputMethodExtension(
974 extension_ime_util::GetInputMethodID("deadbeef", "engine_id"),
975 "deadbeef input method",
981 // Extension IMEs are not enabled by default.
982 EXPECT_EQ(1U, manager_->GetNumActiveInputMethods());
984 std::vector<std::string> extension_ime_ids;
985 extension_ime_ids.push_back(
986 extension_ime_util::GetInputMethodID("deadbeef", "engine_id"));
987 manager_->SetEnabledExtensionImes(&extension_ime_ids);
988 EXPECT_EQ(2U, manager_->GetNumActiveInputMethods());
990 // should be started.
991 EXPECT_EQ(1, mock_ibus_daemon_controller_->start_count());
993 scoped_ptr<InputMethodDescriptors> methods(
994 manager_->GetActiveInputMethods());
995 ASSERT_EQ(2U, methods->size());
996 EXPECT_EQ(extension_ime_util::GetInputMethodID("deadbeef", "engine_id"),
997 // Ext IMEs should be at the end of the list.
998 methods->at(1).id());
1000 manager_->AddInputMethodExtension(
1001 extension_ime_util::GetInputMethodID("cafebabe", "engine_id"),
1002 "cafebabe input method",
1007 EXPECT_EQ(2U, manager_->GetNumActiveInputMethods());
1009 extension_ime_ids.push_back(
1010 extension_ime_util::GetInputMethodID("cafebabe", "engine_id"));
1011 manager_->SetEnabledExtensionImes(&extension_ime_ids);
1012 EXPECT_EQ(3U, manager_->GetNumActiveInputMethods());
1014 scoped_ptr<InputMethodDescriptors> methods(
1015 manager_->GetActiveInputMethods());
1016 ASSERT_EQ(3U, methods->size());
1017 EXPECT_EQ(extension_ime_util::GetInputMethodID("deadbeef", "engine_id"),
1018 // Ext IMEs should be at the end of the list.
1019 methods->at(1).id());
1023 manager_->RemoveInputMethodExtension(
1024 extension_ime_util::GetInputMethodID("deadbeef", "engine_id"));
1025 EXPECT_EQ(2U, manager_->GetNumActiveInputMethods());
1026 manager_->RemoveInputMethodExtension(
1027 extension_ime_util::GetInputMethodID("cafebabe", "engine_id"));
1028 EXPECT_EQ(1U, manager_->GetNumActiveInputMethods());
1029 // Currently, to work around a crash issue at crosbug.com/27051,
1030 // controller_->Stop(); is NOT called when all (extension) IMEs are disabled.
1031 EXPECT_EQ(0, mock_ibus_daemon_controller_->stop_count());
1033 manager_->RemoveObserver(&observer);
1036 TEST_F(InputMethodManagerImplTest, TestAddExtensionInputThenLockScreen) {
1037 TestObserver observer;
1038 InitComponentExtension();
1040 manager_->AddObserver(&observer);
1041 manager_->SetState(InputMethodManager::STATE_BROWSER_SCREEN);
1042 std::vector<std::string> ids;
1043 ids.push_back("xkb:us::eng");
1044 EXPECT_TRUE(manager_->EnableInputMethods(ids));
1045 EXPECT_EQ(1U, manager_->GetNumActiveInputMethods());
1046 EXPECT_EQ(1, observer.input_method_changed_count_);
1047 EXPECT_EQ(ids[0], manager_->GetCurrentInputMethod().id());
1048 EXPECT_EQ("us", xkeyboard_->last_layout_);
1050 // Add an Extension IME.
1051 std::vector<std::string> layouts;
1052 layouts.push_back("us(dvorak)");
1053 std::vector<std::string> languages;
1054 languages.push_back("en-US");
1055 manager_->AddInputMethodExtension(
1056 extension_ime_util::GetInputMethodID("deadbeef", "engine_id"),
1057 "deadbeef input method",
1062 // Extension IME is not enabled by default.
1063 EXPECT_EQ(1U, manager_->GetNumActiveInputMethods());
1064 EXPECT_EQ(1, observer.input_method_changed_count_);
1066 std::vector<std::string> extension_ime_ids;
1067 extension_ime_ids.push_back(
1068 extension_ime_util::GetInputMethodID("deadbeef", "engine_id"));
1069 manager_->SetEnabledExtensionImes(&extension_ime_ids);
1070 EXPECT_EQ(2U, manager_->GetNumActiveInputMethods());
1072 // Switch to the IME.
1073 manager_->SwitchToNextInputMethod();
1074 EXPECT_EQ(3, observer.input_method_changed_count_);
1075 EXPECT_EQ(extension_ime_util::GetInputMethodID("deadbeef", "engine_id"),
1076 manager_->GetCurrentInputMethod().id());
1077 EXPECT_EQ("us(dvorak)", xkeyboard_->last_layout_);
1079 // Lock the screen. This is for crosbug.com/27049.
1080 manager_->SetState(InputMethodManager::STATE_LOCK_SCREEN);
1081 EXPECT_EQ(1U, manager_->GetNumActiveInputMethods()); // Qwerty. No Ext. IME
1082 EXPECT_EQ("xkb:us::eng",
1083 manager_->GetCurrentInputMethod().id());
1084 EXPECT_EQ("us", xkeyboard_->last_layout_);
1085 EXPECT_EQ(0, mock_ibus_daemon_controller_->stop_count());
1087 // Unlock the screen.
1088 manager_->SetState(InputMethodManager::STATE_BROWSER_SCREEN);
1089 EXPECT_EQ(2U, manager_->GetNumActiveInputMethods());
1090 EXPECT_EQ(extension_ime_util::GetInputMethodID("deadbeef", "engine_id"),
1091 manager_->GetCurrentInputMethod().id());
1092 EXPECT_EQ("us(dvorak)", xkeyboard_->last_layout_);
1094 // This is for crosbug.com/27052.
1095 scoped_ptr<InputMethodDescriptors> methods(
1096 manager_->GetActiveInputMethods());
1097 ASSERT_EQ(2U, methods->size());
1098 EXPECT_EQ(extension_ime_util::GetInputMethodID("deadbeef", "engine_id"),
1099 // Ext. IMEs should be at the end of the list.
1100 methods->at(1).id());
1102 manager_->RemoveObserver(&observer);
1105 TEST_F(InputMethodManagerImplTest, TestReset) {
1106 InitComponentExtension();
1108 manager_->SetState(InputMethodManager::STATE_BROWSER_SCREEN);
1109 std::vector<std::string> ids;
1110 ids.push_back("xkb:us::eng");
1111 ids.push_back(nacl_mozc_us_id);
1112 EXPECT_TRUE(manager_->EnableInputMethods(ids));
1113 EXPECT_EQ(2U, manager_->GetNumActiveInputMethods());
1114 EXPECT_EQ(0, mock_engine_handler_->reset_call_count());
1115 manager_->ChangeInputMethod(nacl_mozc_us_id);
1116 EXPECT_EQ(1, mock_ibus_client_->set_global_engine_call_count());
1117 EXPECT_EQ(nacl_mozc_us_id, mock_ibus_client_->latest_global_engine_name());
1118 EXPECT_EQ(0, mock_engine_handler_->reset_call_count());
1119 manager_->ChangeInputMethod("xkb:us::eng");
1120 EXPECT_EQ(1, mock_ibus_client_->set_global_engine_call_count());
1121 EXPECT_EQ(nacl_mozc_us_id, mock_ibus_client_->latest_global_engine_name());
1122 EXPECT_EQ(0, mock_engine_handler_->reset_call_count());
1125 TEST_F(InputMethodManagerImplTest,
1126 ChangeInputMethodBeforeComponentExtensionInitialization_OneIME) {
1127 manager_->SetState(InputMethodManager::STATE_BROWSER_SCREEN);
1128 std::vector<std::string> ids;
1129 ids.push_back(nacl_mozc_us_id);
1130 EXPECT_TRUE(manager_->EnableInputMethods(ids));
1131 EXPECT_EQ(1U, manager_->GetNumActiveInputMethods());
1132 manager_->ChangeInputMethod(nacl_mozc_us_id);
1135 InitComponentExtension();
1136 EXPECT_EQ(1, mock_ibus_client_->set_global_engine_call_count());
1137 EXPECT_EQ(nacl_mozc_us_id, mock_ibus_client_->latest_global_engine_name());
1140 TEST_F(InputMethodManagerImplTest,
1141 ChangeInputMethodBeforeComponentExtensionInitialization_TwoIME) {
1142 manager_->SetState(InputMethodManager::STATE_BROWSER_SCREEN);
1143 std::vector<std::string> ids;
1144 ids.push_back(nacl_mozc_us_id);
1145 ids.push_back(nacl_mozc_jp_id);
1146 EXPECT_TRUE(manager_->EnableInputMethods(ids));
1147 EXPECT_EQ(2U, manager_->GetNumActiveInputMethods());
1148 manager_->ChangeInputMethod(nacl_mozc_us_id);
1149 manager_->ChangeInputMethod(nacl_mozc_jp_id);
1151 InitComponentExtension();
1153 EXPECT_EQ(1, mock_ibus_client_->set_global_engine_call_count());
1154 EXPECT_EQ(nacl_mozc_jp_id, mock_ibus_client_->latest_global_engine_name());
1157 TEST_F(InputMethodManagerImplTest,
1158 ChangeInputMethodBeforeComponentExtensionInitialization_CompOneIME) {
1159 manager_->SetState(InputMethodManager::STATE_BROWSER_SCREEN);
1160 const std::string ext_id =
1161 TestableComponentExtensionIMEManager::GetComponentExtensionIMEId(
1163 ime_list_[0].engines[0].engine_id);
1164 std::vector<std::string> ids;
1165 ids.push_back(ext_id);
1166 EXPECT_TRUE(manager_->EnableInputMethods(ids));
1167 EXPECT_EQ(1U, manager_->GetNumActiveInputMethods());
1168 manager_->ChangeInputMethod(ext_id);
1170 InitComponentExtension();
1172 EXPECT_EQ(1, mock_ibus_client_->set_global_engine_call_count());
1173 EXPECT_EQ(ext_id, mock_ibus_client_->latest_global_engine_name());
1176 TEST_F(InputMethodManagerImplTest,
1177 ChangeInputMethodBeforeComponentExtensionInitialization_CompTwoIME) {
1178 manager_->SetState(InputMethodManager::STATE_BROWSER_SCREEN);
1179 const std::string ext_id1 =
1180 TestableComponentExtensionIMEManager::GetComponentExtensionIMEId(
1182 ime_list_[0].engines[0].engine_id);
1183 const std::string ext_id2 =
1184 TestableComponentExtensionIMEManager::GetComponentExtensionIMEId(
1186 ime_list_[1].engines[0].engine_id);
1187 std::vector<std::string> ids;
1188 ids.push_back(ext_id1);
1189 ids.push_back(ext_id2);
1190 EXPECT_TRUE(manager_->EnableInputMethods(ids));
1191 EXPECT_EQ(2U, manager_->GetNumActiveInputMethods());
1192 manager_->ChangeInputMethod(ext_id1);
1193 manager_->ChangeInputMethod(ext_id2);
1195 InitComponentExtension();
1197 EXPECT_EQ(1, mock_ibus_client_->set_global_engine_call_count());
1198 EXPECT_EQ(ext_id2, mock_ibus_client_->latest_global_engine_name());
1201 TEST_F(InputMethodManagerImplTest,
1202 ChangeInputMethod_ComponenteExtensionOneIME) {
1203 InitComponentExtension();
1205 manager_->SetState(InputMethodManager::STATE_BROWSER_SCREEN);
1206 const std::string ext_id =
1207 TestableComponentExtensionIMEManager::GetComponentExtensionIMEId(
1209 ime_list_[0].engines[0].engine_id);
1210 std::vector<std::string> ids;
1211 ids.push_back(ext_id);
1212 EXPECT_TRUE(manager_->EnableInputMethods(ids));
1213 EXPECT_EQ(1U, manager_->GetNumActiveInputMethods());
1214 EXPECT_EQ(1, mock_ibus_client_->set_global_engine_call_count());
1215 EXPECT_EQ(ext_id, mock_ibus_client_->latest_global_engine_name());
1218 TEST_F(InputMethodManagerImplTest,
1219 ChangeInputMethod_ComponenteExtensionTwoIME) {
1220 InitComponentExtension();
1222 manager_->SetState(InputMethodManager::STATE_BROWSER_SCREEN);
1223 const std::string ext_id1 =
1224 TestableComponentExtensionIMEManager::GetComponentExtensionIMEId(
1226 ime_list_[0].engines[0].engine_id);
1227 const std::string ext_id2 =
1228 TestableComponentExtensionIMEManager::GetComponentExtensionIMEId(
1230 ime_list_[1].engines[0].engine_id);
1231 std::vector<std::string> ids;
1232 ids.push_back(ext_id1);
1233 ids.push_back(ext_id2);
1234 EXPECT_TRUE(manager_->EnableInputMethods(ids));
1235 EXPECT_EQ(2U, manager_->GetNumActiveInputMethods());
1236 EXPECT_EQ(1, mock_ibus_client_->set_global_engine_call_count());
1237 EXPECT_EQ(ext_id1, mock_ibus_client_->latest_global_engine_name());
1238 manager_->ChangeInputMethod(ext_id2);
1239 EXPECT_EQ(2, mock_ibus_client_->set_global_engine_call_count());
1240 EXPECT_EQ(ext_id2, mock_ibus_client_->latest_global_engine_name());
1243 TEST_F(InputMethodManagerImplTest,
1244 AsyncComponentExtentionInitializeBeforeIBusDaemonConnection) {
1245 const std::string xkb_id = "xkb:cz::cze";
1246 const std::string ime_id = nacl_mozc_us_id;
1247 const std::string fallback_id = "xkb:us::eng";
1248 std::vector<std::string> ids;
1249 ids.push_back(xkb_id);
1250 ids.push_back(ime_id);
1251 EXPECT_TRUE(manager_->EnableInputMethods(ids));
1253 // If component extension IME is not initialized, even XKB layout cannot be
1255 manager_->ChangeInputMethod(xkb_id);
1256 EXPECT_EQ(fallback_id, manager_->GetCurrentInputMethod().id());
1258 // After component extension IME is initialized, previous input method should
1259 // be automatically enabled.
1260 InitComponentExtension();
1261 EXPECT_EQ(xkb_id, manager_->GetCurrentInputMethod().id());
1263 // However input method should not be enabled before establishment of
1264 // connection with ibus-daemon.
1265 manager_->ChangeInputMethod(ime_id);
1266 // TODO(nona): Write expectation, GetCurrentInputMethod returns |ime_id| even
1267 // the actual input method is not changed.
1269 // After connection with ibus-daemon is established, previous specified input
1270 // method should be enabled automatically.
1272 EXPECT_EQ(ime_id, manager_->GetCurrentInputMethod().id());
1275 TEST_F(InputMethodManagerImplTest,
1276 AsyncComponentExtentionInitializeAfterIBusDaemonConnection) {
1277 const std::string xkb_id = "xkb:cz::cze";
1278 const std::string ime_id = nacl_mozc_us_id;
1279 const std::string fallback_id = "xkb:us::eng";
1280 std::vector<std::string> ids;
1281 ids.push_back(xkb_id);
1282 ids.push_back(ime_id);
1283 EXPECT_TRUE(manager_->EnableInputMethods(ids));
1285 // If component extension IME is not initialized, even XKB layout cannot be
1287 manager_->ChangeInputMethod(xkb_id);
1288 EXPECT_EQ(fallback_id, manager_->GetCurrentInputMethod().id());
1290 // Even after connection with ibus-daemon is established, ChangeInputMethod do
1291 // nothing without component extension IME initialization.
1293 EXPECT_EQ(fallback_id, manager_->GetCurrentInputMethod().id());
1295 // After component extension IME is initialized, previous specified input
1296 // method should be automatically enabled.
1297 InitComponentExtension();
1298 EXPECT_EQ(xkb_id, manager_->GetCurrentInputMethod().id());
1301 } // namespace input_method
1302 } // namespace chromeos