Update To 11.40.268.0
[platform/framework/web/crosswalk.git] / src / chrome / browser / chromeos / input_method / input_method_manager_impl_unittest.cc
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.
4
5 #include "chrome/browser/chromeos/input_method/input_method_manager_impl.h"
6
7 #include <algorithm>
8
9 #include "ash/ime/input_method_menu_item.h"
10 #include "ash/ime/input_method_menu_manager.h"
11 #include "base/basictypes.h"
12 #include "base/bind.h"
13 #include "base/bind_helpers.h"
14 #include "base/compiler_specific.h"
15 #include "base/logging.h"
16 #include "base/memory/scoped_ptr.h"
17 #include "base/message_loop/message_loop.h"
18 #include "base/run_loop.h"
19 #include "chrome/browser/chromeos/input_method/input_method_engine_interface.h"
20 #include "chrome/browser/chromeos/input_method/mock_candidate_window_controller.h"
21 #include "chrome/browser/chromeos/input_method/mock_input_method_engine.h"
22 #include "chrome/test/base/browser_with_test_window_test.h"
23 #include "chrome/test/base/testing_browser_process.h"
24 #include "chrome/test/base/testing_profile.h"
25 #include "chrome/test/base/testing_profile_manager.h"
26 #include "chromeos/ime/extension_ime_util.h"
27 #include "chromeos/ime/fake_ime_keyboard.h"
28 #include "chromeos/ime/fake_input_method_delegate.h"
29 #include "chromeos/ime/mock_component_extension_ime_manager_delegate.h"
30 #include "testing/gtest/include/gtest/gtest.h"
31 #include "ui/base/accelerators/accelerator.h"
32 #include "ui/base/ime/chromeos/mock_ime_engine_handler.h"
33 #include "ui/base/ime/input_method_initializer.h"
34 #include "ui/events/keycodes/keyboard_codes.h"
35
36 namespace chromeos {
37
38 namespace input_method {
39 namespace {
40
41 const char kNaclMozcUsId[] = "nacl_mozc_us";
42 const char kNaclMozcJpId[] = "nacl_mozc_jp";
43 const char kExt2Engine1Id[] = "ext2_engine1-t-i0-engine_id";
44 const char kExt2Engine2Id[] = "ext2_engine2-t-i0-engine_id";
45 const char kPinyinImeId[] = "zh-t-i0-pinyin";
46 const char kExtensionId1[] = "00000000000000000000000000000000";
47 const char kExtensionId2[] = "11111111111111111111111111111111";
48
49 // Returns true if |descriptors| contain |target|.
50 bool Contain(const InputMethodDescriptors& descriptors,
51              const InputMethodDescriptor& target) {
52   for (size_t i = 0; i < descriptors.size(); ++i) {
53     if (descriptors[i].id() == target.id())
54       return true;
55   }
56   return false;
57 }
58
59 std::string ImeIdFromEngineId(const std::string& id) {
60   return extension_ime_util::GetInputMethodIDByEngineID(id);
61 }
62
63 class TestObserver : public InputMethodManager::Observer,
64                      public ash::ime::InputMethodMenuManager::Observer {
65  public:
66   TestObserver()
67       : input_method_changed_count_(0),
68         input_method_menu_item_changed_count_(0),
69         last_show_message_(false) {
70   }
71   virtual ~TestObserver() {}
72
73   virtual void InputMethodChanged(InputMethodManager* manager,
74                                   bool show_message) override {
75     ++input_method_changed_count_;
76     last_show_message_ = show_message;
77   }
78   virtual void InputMethodMenuItemChanged(
79       ash::ime::InputMethodMenuManager* manager) override {
80     ++input_method_menu_item_changed_count_;
81   }
82
83   int input_method_changed_count_;
84   int input_method_menu_item_changed_count_;
85   bool last_show_message_;
86
87  private:
88   DISALLOW_COPY_AND_ASSIGN(TestObserver);
89 };
90
91 class TestCandidateWindowObserver
92     : public InputMethodManager::CandidateWindowObserver {
93  public:
94   TestCandidateWindowObserver()
95       : candidate_window_opened_count_(0),
96         candidate_window_closed_count_(0) {
97   }
98
99   virtual ~TestCandidateWindowObserver() {}
100
101   virtual void CandidateWindowOpened(InputMethodManager* manager) override {
102     ++candidate_window_opened_count_;
103   }
104   virtual void CandidateWindowClosed(InputMethodManager* manager) override {
105     ++candidate_window_closed_count_;
106   }
107
108   int candidate_window_opened_count_;
109   int candidate_window_closed_count_;
110
111  private:
112   DISALLOW_COPY_AND_ASSIGN(TestCandidateWindowObserver);
113 };
114 }  // namespace
115
116 class InputMethodManagerImplTest :  public BrowserWithTestWindowTest {
117  public:
118   InputMethodManagerImplTest()
119       : delegate_(NULL),
120         candidate_window_controller_(NULL),
121         keyboard_(NULL) {
122   }
123   virtual ~InputMethodManagerImplTest() {}
124
125   virtual void SetUp() override {
126     profile_manager_.reset(new TestingProfileManager(GetBrowserProcess()));
127     ASSERT_TRUE(profile_manager_->SetUp());
128
129     ui::InitializeInputMethodForTesting();
130
131     delegate_ = new FakeInputMethodDelegate();
132     manager_.reset(new InputMethodManagerImpl(
133         scoped_ptr<InputMethodDelegate>(delegate_), false));
134     manager_->GetInputMethodUtil()->UpdateHardwareLayoutCache();
135     candidate_window_controller_ = new MockCandidateWindowController;
136     manager_->SetCandidateWindowControllerForTesting(
137         candidate_window_controller_);
138     keyboard_ = new FakeImeKeyboard;
139     manager_->SetImeKeyboardForTesting(keyboard_);
140     mock_engine_handler_.reset(new MockInputMethodEngine());
141     IMEBridge::Initialize();
142     IMEBridge::Get()->SetCurrentEngineHandler(mock_engine_handler_.get());
143
144     menu_manager_ = ash::ime::InputMethodMenuManager::GetInstance();
145
146     InitImeList();
147
148     BrowserWithTestWindowTest::SetUp();
149   }
150
151   virtual void TearDown() override {
152     BrowserWithTestWindowTest::TearDown();
153
154     ui::ShutdownInputMethodForTesting();
155
156     delegate_ = NULL;
157     candidate_window_controller_ = NULL;
158     keyboard_ = NULL;
159     manager_.reset();
160
161     profile_manager_.reset();
162   }
163
164  protected:
165   // Helper function to initialize component extension stuff for testing.
166   void InitComponentExtension() {
167     mock_delegate_ = new MockComponentExtIMEManagerDelegate();
168     mock_delegate_->set_ime_list(ime_list_);
169     scoped_ptr<ComponentExtensionIMEManagerDelegate> delegate(mock_delegate_);
170
171     // CreateNewState(NULL) returns state with non-empty current_input_method.
172     // So SetState() triggers ChangeInputMethod().
173     manager_->SetState(manager_->CreateNewState(NULL));
174
175     std::vector<std::string> layouts;
176     layouts.push_back("us");
177     std::vector<std::string> languages;
178     languages.push_back("en-US");
179
180     // Note, for production, these SetEngineHandler are called when
181     // IMEEngineHandlerInterface is initialized via
182     // InitializeComponentextension.
183     InputMethodDescriptors descriptors;
184     manager_->GetActiveIMEState()->AddInputMethodExtension(
185         ImeIdFromEngineId(kNaclMozcUsId),
186         descriptors,
187         mock_engine_handler_.get());
188     manager_->GetActiveIMEState()->AddInputMethodExtension(
189         ImeIdFromEngineId(kExt2Engine1Id),
190         descriptors,
191         mock_engine_handler_.get());
192     manager_->InitializeComponentExtensionForTesting(delegate.Pass());
193   }
194
195   void InitImeList() {
196     ime_list_.clear();
197
198     ComponentExtensionIME ext_xkb;
199     ext_xkb.id = extension_ime_util::kXkbExtensionId;
200     ext_xkb.description = "ext_xkb_description";
201     ext_xkb.path = base::FilePath("ext_xkb_file_path");
202
203     ComponentExtensionEngine ext_xkb_engine_us;
204     ext_xkb_engine_us.engine_id = "xkb:us::eng";
205     ext_xkb_engine_us.display_name = "xkb:us::eng";
206     ext_xkb_engine_us.language_codes.push_back("en-US");
207     ext_xkb_engine_us.layouts.push_back("us");
208     ext_xkb.engines.push_back(ext_xkb_engine_us);
209
210     ComponentExtensionEngine ext_xkb_engine_intl;
211     ext_xkb_engine_intl.engine_id = "xkb:us:intl:eng";
212     ext_xkb_engine_intl.display_name = "xkb:us:intl:eng";
213     ext_xkb_engine_intl.language_codes.push_back("en-US");
214     ext_xkb_engine_intl.layouts.push_back("us(intl)");
215     ext_xkb.engines.push_back(ext_xkb_engine_intl);
216
217     ComponentExtensionEngine ext_xkb_engine_altgr_intl;
218     ext_xkb_engine_altgr_intl.engine_id = "xkb:us:altgr-intl:eng";
219     ext_xkb_engine_altgr_intl.display_name = "xkb:us:altgr-intl:eng";
220     ext_xkb_engine_altgr_intl.language_codes.push_back("en-US");
221     ext_xkb_engine_altgr_intl.layouts.push_back("us(altgr-intl)");
222     ext_xkb.engines.push_back(ext_xkb_engine_altgr_intl);
223
224     ComponentExtensionEngine ext_xkb_engine_dvorak;
225     ext_xkb_engine_dvorak.engine_id = "xkb:us:dvorak:eng";
226     ext_xkb_engine_dvorak.display_name = "xkb:us:dvorak:eng";
227     ext_xkb_engine_dvorak.language_codes.push_back("en-US");
228     ext_xkb_engine_dvorak.layouts.push_back("us(dvorak)");
229     ext_xkb.engines.push_back(ext_xkb_engine_dvorak);
230
231     ComponentExtensionEngine ext_xkb_engine_colemak;
232     ext_xkb_engine_colemak.engine_id = "xkb:us:colemak:eng";
233     ext_xkb_engine_colemak.display_name = "xkb:us:colemak:eng";
234     ext_xkb_engine_colemak.language_codes.push_back("en-US");
235     ext_xkb_engine_colemak.layouts.push_back("us(colemak)");
236     ext_xkb.engines.push_back(ext_xkb_engine_colemak);
237
238     ComponentExtensionEngine ext_xkb_engine_fr;
239     ext_xkb_engine_fr.engine_id = "xkb:fr::fra";
240     ext_xkb_engine_fr.display_name = "xkb:fr::fra";
241     ext_xkb_engine_fr.language_codes.push_back("fr");
242     ext_xkb_engine_fr.layouts.push_back("fr");
243     ext_xkb.engines.push_back(ext_xkb_engine_fr);
244
245     ComponentExtensionEngine ext_xkb_engine_se;
246     ext_xkb_engine_se.engine_id = "xkb:se::swe";
247     ext_xkb_engine_se.display_name = "xkb:se::swe";
248     ext_xkb_engine_se.language_codes.push_back("sv");
249     ext_xkb_engine_se.layouts.push_back("se");
250     ext_xkb.engines.push_back(ext_xkb_engine_se);
251
252     ComponentExtensionEngine ext_xkb_engine_jp;
253     ext_xkb_engine_jp.engine_id = "xkb:jp::jpn";
254     ext_xkb_engine_jp.display_name = "xkb:jp::jpn";
255     ext_xkb_engine_jp.language_codes.push_back("ja");
256     ext_xkb_engine_jp.layouts.push_back("jp");
257     ext_xkb.engines.push_back(ext_xkb_engine_jp);
258
259     ComponentExtensionEngine ext_xkb_engine_ru;
260     ext_xkb_engine_ru.engine_id = "xkb:ru::rus";
261     ext_xkb_engine_ru.display_name = "xkb:ru::rus";
262     ext_xkb_engine_ru.language_codes.push_back("ru");
263     ext_xkb_engine_ru.layouts.push_back("ru");
264     ext_xkb.engines.push_back(ext_xkb_engine_ru);
265
266     ComponentExtensionEngine ext_xkb_engine_hu;
267     ext_xkb_engine_hu.engine_id = "xkb:hu::hun";
268     ext_xkb_engine_hu.display_name = "xkb:hu::hun";
269     ext_xkb_engine_hu.language_codes.push_back("hu");
270     ext_xkb_engine_hu.layouts.push_back("hu");
271     ext_xkb.engines.push_back(ext_xkb_engine_hu);
272
273     ime_list_.push_back(ext_xkb);
274
275     ComponentExtensionIME ext1;
276     ext1.id = extension_ime_util::kMozcExtensionId;
277     ext1.description = "ext1_description";
278     ext1.path = base::FilePath("ext1_file_path");
279
280     ComponentExtensionEngine ext1_engine1;
281     ext1_engine1.engine_id = "nacl_mozc_us";
282     ext1_engine1.display_name = "ext1_engine_1_display_name";
283     ext1_engine1.language_codes.push_back("ja");
284     ext1_engine1.layouts.push_back("us");
285     ext1.engines.push_back(ext1_engine1);
286
287     ComponentExtensionEngine ext1_engine2;
288     ext1_engine2.engine_id = "nacl_mozc_jp";
289     ext1_engine2.display_name = "ext1_engine_1_display_name";
290     ext1_engine2.language_codes.push_back("ja");
291     ext1_engine2.layouts.push_back("jp");
292     ext1.engines.push_back(ext1_engine2);
293
294     ime_list_.push_back(ext1);
295
296     ComponentExtensionIME ext2;
297     ext2.id = extension_ime_util::kT13nExtensionId;
298     ext2.description = "ext2_description";
299     ext2.path = base::FilePath("ext2_file_path");
300
301     ComponentExtensionEngine ext2_engine1;
302     ext2_engine1.engine_id = kExt2Engine1Id;
303     ext2_engine1.display_name = "ext2_engine_1_display_name";
304     ext2_engine1.language_codes.push_back("en");
305     ext2_engine1.layouts.push_back("us");
306     ext2.engines.push_back(ext2_engine1);
307
308     ComponentExtensionEngine ext2_engine2;
309     ext2_engine2.engine_id = kExt2Engine2Id;
310     ext2_engine2.display_name = "ext2_engine_2_display_name";
311     ext2_engine2.language_codes.push_back("en");
312     ext2_engine2.layouts.push_back("us(dvorak)");
313     ext2.engines.push_back(ext2_engine2);
314
315     ime_list_.push_back(ext2);
316   }
317
318   TestingBrowserProcess* GetBrowserProcess() {
319     return TestingBrowserProcess::GetGlobal();
320   }
321
322   scoped_ptr<TestingProfileManager> profile_manager_;
323   scoped_ptr<InputMethodManagerImpl> manager_;
324   FakeInputMethodDelegate* delegate_;
325   MockCandidateWindowController* candidate_window_controller_;
326   scoped_ptr<MockInputMethodEngine> mock_engine_handler_;
327   FakeImeKeyboard* keyboard_;
328   MockComponentExtIMEManagerDelegate* mock_delegate_;
329   std::vector<ComponentExtensionIME> ime_list_;
330   ash::ime::InputMethodMenuManager* menu_manager_;
331
332  private:
333   DISALLOW_COPY_AND_ASSIGN(InputMethodManagerImplTest);
334 };
335
336 TEST_F(InputMethodManagerImplTest, TestGetImeKeyboard) {
337   EXPECT_TRUE(manager_->GetImeKeyboard());
338   EXPECT_EQ(keyboard_, manager_->GetImeKeyboard());
339 }
340
341 TEST_F(InputMethodManagerImplTest, TestCandidateWindowObserver) {
342   TestCandidateWindowObserver observer;
343   candidate_window_controller_->NotifyCandidateWindowOpened();  // nop
344   candidate_window_controller_->NotifyCandidateWindowClosed();  // nop
345   manager_->AddCandidateWindowObserver(&observer);
346   candidate_window_controller_->NotifyCandidateWindowOpened();
347   EXPECT_EQ(1, observer.candidate_window_opened_count_);
348   candidate_window_controller_->NotifyCandidateWindowClosed();
349   EXPECT_EQ(1, observer.candidate_window_closed_count_);
350   candidate_window_controller_->NotifyCandidateWindowOpened();
351   EXPECT_EQ(2, observer.candidate_window_opened_count_);
352   candidate_window_controller_->NotifyCandidateWindowClosed();
353   EXPECT_EQ(2, observer.candidate_window_closed_count_);
354   manager_->RemoveCandidateWindowObserver(&observer);
355 }
356
357 TEST_F(InputMethodManagerImplTest, TestObserver) {
358   // For http://crbug.com/19655#c11 - (3). browser_state_monitor_unittest.cc is
359   // also for the scenario.
360   std::vector<std::string> keyboard_layouts;
361   keyboard_layouts.push_back("xkb:us::eng");
362
363   TestObserver observer;
364   InitComponentExtension();
365   manager_->AddObserver(&observer);
366   menu_manager_->AddObserver(&observer);
367   EXPECT_EQ(0, observer.input_method_changed_count_);
368   manager_->GetActiveIMEState()->EnableLoginLayouts("en-US", keyboard_layouts);
369   EXPECT_EQ(5U, manager_->GetActiveIMEState()->GetActiveInputMethods()->size());
370   EXPECT_EQ(1, observer.input_method_changed_count_);
371   // Menu change is triggered only if current input method was actually changed.
372   EXPECT_EQ(0, observer.input_method_menu_item_changed_count_);
373   manager_->GetActiveIMEState()->ChangeInputMethod(
374       ImeIdFromEngineId("xkb:us:dvorak:eng"), false /* show_message */);
375   EXPECT_FALSE(observer.last_show_message_);
376   EXPECT_EQ(2, observer.input_method_changed_count_);
377   EXPECT_EQ(1, observer.input_method_menu_item_changed_count_);
378   manager_->GetActiveIMEState()->ChangeInputMethod(
379       ImeIdFromEngineId("xkb:us:dvorak:eng"), false /* show_message */);
380   EXPECT_FALSE(observer.last_show_message_);
381
382   // The observer is always notified even when the same input method ID is
383   // passed to ChangeInputMethod() more than twice.
384   // TODO(komatsu): Revisit if this is neccessary.
385   EXPECT_EQ(3, observer.input_method_changed_count_);
386
387   // If the same input method ID is passed, PropertyChanged() is not
388   // notified.
389   EXPECT_EQ(1, observer.input_method_menu_item_changed_count_);
390
391   manager_->RemoveObserver(&observer);
392   menu_manager_->RemoveObserver(&observer);
393 }
394
395 TEST_F(InputMethodManagerImplTest, TestGetSupportedInputMethods) {
396   InitComponentExtension();
397   InputMethodDescriptors methods;
398   methods = manager_->GetComponentExtensionIMEManager()
399                 ->GetXkbIMEAsInputMethodDescriptor();
400   // Try to find random 4-5 layuts and IMEs to make sure the returned list is
401   // correct.
402   const InputMethodDescriptor* id_to_find =
403       manager_->GetInputMethodUtil()->GetInputMethodDescriptorFromId(
404           ImeIdFromEngineId(kNaclMozcUsId));
405   id_to_find = manager_->GetInputMethodUtil()->GetInputMethodDescriptorFromId(
406       ImeIdFromEngineId("xkb:us::eng"));
407   EXPECT_TRUE(Contain(methods, *id_to_find));
408   id_to_find = manager_->GetInputMethodUtil()->GetInputMethodDescriptorFromId(
409       ImeIdFromEngineId("xkb:us:dvorak:eng"));
410   EXPECT_TRUE(Contain(methods, *id_to_find));
411   id_to_find = manager_->GetInputMethodUtil()->GetInputMethodDescriptorFromId(
412       ImeIdFromEngineId("xkb:fr::fra"));
413   EXPECT_TRUE(Contain(methods, *id_to_find));
414 }
415
416 TEST_F(InputMethodManagerImplTest, TestEnableLayouts) {
417   // Currently 5 keyboard layouts are supported for en-US, and 1 for ja. See
418   // ibus_input_method.txt.
419   std::vector<std::string> keyboard_layouts;
420
421   InitComponentExtension();
422   manager_->GetActiveIMEState()->EnableLoginLayouts("en-US", keyboard_layouts);
423   EXPECT_EQ(5U, manager_->GetActiveIMEState()->GetNumActiveInputMethods());
424
425   // For http://crbug.com/19655#c11 - (5)
426   // The hardware keyboard layout "xkb:us::eng" is always active, hence 2U.
427   manager_->GetActiveIMEState()->EnableLoginLayouts(
428       "ja", keyboard_layouts);  // Japanese
429   EXPECT_EQ(2U, manager_->GetActiveIMEState()->GetNumActiveInputMethods());
430 }
431
432 TEST_F(InputMethodManagerImplTest, TestEnableLayoutsAndCurrentInputMethod) {
433   // For http://crbug.com/329061
434   std::vector<std::string> keyboard_layouts;
435   keyboard_layouts.push_back(ImeIdFromEngineId("xkb:se::swe"));
436
437   InitComponentExtension();
438   manager_->GetActiveIMEState()->EnableLoginLayouts("en-US", keyboard_layouts);
439   const std::string im_id =
440       manager_->GetActiveIMEState()->GetCurrentInputMethod().id();
441   EXPECT_EQ(ImeIdFromEngineId("xkb:se::swe"), im_id);
442 }
443
444 TEST_F(InputMethodManagerImplTest, TestEnableLayoutsNonUsHardwareKeyboard) {
445   InitComponentExtension();
446   // The physical layout is French.
447   manager_->GetInputMethodUtil()->SetHardwareKeyboardLayoutForTesting(
448       "xkb:fr::fra");
449   manager_->GetActiveIMEState()->EnableLoginLayouts(
450       "en-US",
451       manager_->GetInputMethodUtil()->GetHardwareLoginInputMethodIds());
452   EXPECT_EQ(
453       6U,
454       manager_->GetActiveIMEState()->GetNumActiveInputMethods());  // 5 + French
455   // The physical layout is Japanese.
456   manager_->GetInputMethodUtil()->SetHardwareKeyboardLayoutForTesting(
457       "xkb:jp::jpn");
458   manager_->GetActiveIMEState()->EnableLoginLayouts(
459       "ja", manager_->GetInputMethodUtil()->GetHardwareLoginInputMethodIds());
460   // "xkb:us::eng" is not needed, hence 1.
461   EXPECT_EQ(1U, manager_->GetActiveIMEState()->GetNumActiveInputMethods());
462
463   // The physical layout is Russian.
464   manager_->GetInputMethodUtil()->SetHardwareKeyboardLayoutForTesting(
465       "xkb:ru::rus");
466   manager_->GetActiveIMEState()->EnableLoginLayouts(
467       "ru", manager_->GetInputMethodUtil()->GetHardwareLoginInputMethodIds());
468   // "xkb:us::eng" only.
469   EXPECT_EQ(1U, manager_->GetActiveIMEState()->GetNumActiveInputMethods());
470   EXPECT_EQ(ImeIdFromEngineId("xkb:us::eng"),
471             manager_->GetActiveIMEState()->GetActiveInputMethodIds().front());
472 }
473
474 TEST_F(InputMethodManagerImplTest, TestEnableMultipleHardwareKeyboardLayout) {
475   InitComponentExtension();
476   // The physical layouts are French and Hungarian.
477   manager_->GetInputMethodUtil()->SetHardwareKeyboardLayoutForTesting(
478       "xkb:fr::fra,xkb:hu::hun");
479   manager_->GetActiveIMEState()->EnableLoginLayouts(
480       "en-US",
481       manager_->GetInputMethodUtil()->GetHardwareLoginInputMethodIds());
482   // 5 + French + Hungarian
483   EXPECT_EQ(7U, manager_->GetActiveIMEState()->GetNumActiveInputMethods());
484 }
485
486 TEST_F(InputMethodManagerImplTest,
487        TestEnableMultipleHardwareKeyboardLayout_NoLoginKeyboard) {
488   InitComponentExtension();
489   // The physical layouts are English (US) and Russian.
490   manager_->GetInputMethodUtil()->SetHardwareKeyboardLayoutForTesting(
491       "xkb:us::eng,xkb:ru::rus");
492   manager_->GetActiveIMEState()->EnableLoginLayouts(
493       "ru", manager_->GetInputMethodUtil()->GetHardwareLoginInputMethodIds());
494   // xkb:us:eng
495   EXPECT_EQ(1U, manager_->GetActiveIMEState()->GetNumActiveInputMethods());
496 }
497
498 TEST_F(InputMethodManagerImplTest, TestActiveInputMethods) {
499   InitComponentExtension();
500   std::vector<std::string> keyboard_layouts;
501   manager_->GetActiveIMEState()->EnableLoginLayouts(
502       "ja", keyboard_layouts);  // Japanese
503   EXPECT_EQ(2U, manager_->GetActiveIMEState()->GetNumActiveInputMethods());
504   scoped_ptr<InputMethodDescriptors> methods(
505       manager_->GetActiveIMEState()->GetActiveInputMethods());
506   ASSERT_TRUE(methods.get());
507   EXPECT_EQ(2U, methods->size());
508   const InputMethodDescriptor* id_to_find =
509       manager_->GetInputMethodUtil()->GetInputMethodDescriptorFromId(
510           ImeIdFromEngineId("xkb:us::eng"));
511   EXPECT_TRUE(id_to_find && Contain(*methods.get(), *id_to_find));
512   id_to_find = manager_->GetInputMethodUtil()->GetInputMethodDescriptorFromId(
513       ImeIdFromEngineId("xkb:jp::jpn"));
514   EXPECT_TRUE(id_to_find && Contain(*methods.get(), *id_to_find));
515 }
516
517 TEST_F(InputMethodManagerImplTest, TestEnableTwoLayouts) {
518   // For http://crbug.com/19655#c11 - (8), step 6.
519   TestObserver observer;
520   InitComponentExtension();
521   manager_->AddObserver(&observer);
522   manager_->SetUISessionState(InputMethodManager::STATE_BROWSER_SCREEN);
523   std::vector<std::string> ids;
524   ids.push_back(ImeIdFromEngineId("xkb:us:dvorak:eng"));
525   ids.push_back(ImeIdFromEngineId("xkb:us:colemak:eng"));
526   EXPECT_TRUE(manager_->GetActiveIMEState()->ReplaceEnabledInputMethods(ids));
527   EXPECT_EQ(2U, manager_->GetActiveIMEState()->GetNumActiveInputMethods());
528   // Since all the IDs added avobe are keyboard layouts, Start() should not be
529   // called.
530   EXPECT_EQ(1, observer.input_method_changed_count_);
531   EXPECT_EQ(ImeIdFromEngineId(ids[0]),
532             manager_->GetActiveIMEState()->GetCurrentInputMethod().id());
533   EXPECT_EQ("us(dvorak)", keyboard_->last_layout_);
534   // Disable Dvorak.
535   ids.erase(ids.begin());
536   EXPECT_TRUE(manager_->GetActiveIMEState()->ReplaceEnabledInputMethods(ids));
537   EXPECT_EQ(1U, manager_->GetActiveIMEState()->GetNumActiveInputMethods());
538   EXPECT_EQ(2, observer.input_method_changed_count_);
539   EXPECT_EQ(ImeIdFromEngineId(ids[0]),  // colemak
540             manager_->GetActiveIMEState()->GetCurrentInputMethod().id());
541   EXPECT_EQ("us(colemak)", keyboard_->last_layout_);
542   manager_->RemoveObserver(&observer);
543 }
544
545 TEST_F(InputMethodManagerImplTest, TestEnableThreeLayouts) {
546   // For http://crbug.com/19655#c11 - (9).
547   TestObserver observer;
548   InitComponentExtension();
549   manager_->AddObserver(&observer);
550   manager_->SetUISessionState(InputMethodManager::STATE_BROWSER_SCREEN);
551   std::vector<std::string> ids;
552   ids.push_back(ImeIdFromEngineId("xkb:us::eng"));
553   ids.push_back(ImeIdFromEngineId("xkb:us:dvorak:eng"));
554   ids.push_back(ImeIdFromEngineId("xkb:us:colemak:eng"));
555   EXPECT_TRUE(manager_->GetActiveIMEState()->ReplaceEnabledInputMethods(ids));
556   EXPECT_EQ(3U, manager_->GetActiveIMEState()->GetNumActiveInputMethods());
557   EXPECT_EQ(1, observer.input_method_changed_count_);
558   EXPECT_EQ(ImeIdFromEngineId(ids[0]),
559             manager_->GetActiveIMEState()->GetCurrentInputMethod().id());
560   EXPECT_EQ("us", keyboard_->last_layout_);
561   // Switch to Dvorak.
562   manager_->GetActiveIMEState()->SwitchToNextInputMethod();
563   EXPECT_EQ(2, observer.input_method_changed_count_);
564   EXPECT_EQ(ImeIdFromEngineId(ids[1]),
565             manager_->GetActiveIMEState()->GetCurrentInputMethod().id());
566   EXPECT_EQ("us(dvorak)", keyboard_->last_layout_);
567   // Disable Dvorak.
568   ids.erase(ids.begin() + 1);
569   EXPECT_TRUE(manager_->GetActiveIMEState()->ReplaceEnabledInputMethods(ids));
570   EXPECT_EQ(2U, manager_->GetActiveIMEState()->GetNumActiveInputMethods());
571   EXPECT_EQ(3, observer.input_method_changed_count_);
572   EXPECT_EQ(ImeIdFromEngineId(ids[0]),  // US Qwerty
573             manager_->GetActiveIMEState()->GetCurrentInputMethod().id());
574   EXPECT_EQ("us", keyboard_->last_layout_);
575   manager_->RemoveObserver(&observer);
576 }
577
578 TEST_F(InputMethodManagerImplTest, TestEnableLayoutAndIme) {
579   // For http://crbug.com/19655#c11 - (10).
580   TestObserver observer;
581   InitComponentExtension();
582   manager_->AddObserver(&observer);
583   manager_->SetUISessionState(InputMethodManager::STATE_BROWSER_SCREEN);
584   std::vector<std::string> ids;
585   ids.push_back(ImeIdFromEngineId("xkb:us:dvorak:eng"));
586   ids.push_back(ImeIdFromEngineId(kNaclMozcUsId));
587   EXPECT_TRUE(manager_->GetActiveIMEState()->ReplaceEnabledInputMethods(ids));
588   EXPECT_EQ(1, observer.input_method_changed_count_);
589   EXPECT_EQ(ImeIdFromEngineId(ids[0]),
590             manager_->GetActiveIMEState()->GetCurrentInputMethod().id());
591   EXPECT_EQ("us(dvorak)", keyboard_->last_layout_);
592   // Switch to Mozc
593   manager_->GetActiveIMEState()->SwitchToNextInputMethod();
594   EXPECT_EQ(2, observer.input_method_changed_count_);
595   EXPECT_EQ(ImeIdFromEngineId(ids[1]),
596             manager_->GetActiveIMEState()->GetCurrentInputMethod().id());
597   EXPECT_EQ("us", keyboard_->last_layout_);
598   // Disable Mozc.
599   ids.erase(ids.begin() + 1);
600   EXPECT_TRUE(manager_->GetActiveIMEState()->ReplaceEnabledInputMethods(ids));
601   EXPECT_EQ(1U, manager_->GetActiveIMEState()->GetNumActiveInputMethods());
602   EXPECT_EQ(ImeIdFromEngineId(ids[0]),
603             manager_->GetActiveIMEState()->GetCurrentInputMethod().id());
604   EXPECT_EQ("us(dvorak)", keyboard_->last_layout_);
605 }
606
607 TEST_F(InputMethodManagerImplTest, TestEnableLayoutAndIme2) {
608   // For http://crbug.com/19655#c11 - (11).
609   TestObserver observer;
610   InitComponentExtension();
611   manager_->AddObserver(&observer);
612   manager_->SetUISessionState(InputMethodManager::STATE_BROWSER_SCREEN);
613   std::vector<std::string> ids;
614   ids.push_back(ImeIdFromEngineId("xkb:us:dvorak:eng"));
615   ids.push_back(ImeIdFromEngineId(kNaclMozcUsId));
616   EXPECT_TRUE(manager_->GetActiveIMEState()->ReplaceEnabledInputMethods(ids));
617   EXPECT_EQ(1, observer.input_method_changed_count_);
618   EXPECT_EQ(ImeIdFromEngineId(ids[0]),
619             manager_->GetActiveIMEState()->GetCurrentInputMethod().id());
620   EXPECT_EQ("us(dvorak)", keyboard_->last_layout_);
621
622   // Disable Dvorak.
623   ids.erase(ids.begin());
624   EXPECT_TRUE(manager_->GetActiveIMEState()->ReplaceEnabledInputMethods(ids));
625   EXPECT_EQ(1U, manager_->GetActiveIMEState()->GetNumActiveInputMethods());
626   EXPECT_EQ(ImeIdFromEngineId(ids[0]),  // Mozc
627             manager_->GetActiveIMEState()->GetCurrentInputMethod().id());
628   EXPECT_EQ("us", keyboard_->last_layout_);
629   manager_->RemoveObserver(&observer);
630 }
631
632 TEST_F(InputMethodManagerImplTest, TestEnableImes) {
633   TestObserver observer;
634   InitComponentExtension();
635   manager_->AddObserver(&observer);
636   manager_->SetUISessionState(InputMethodManager::STATE_BROWSER_SCREEN);
637   std::vector<std::string> ids;
638   ids.push_back(ImeIdFromEngineId(kExt2Engine1Id));
639   ids.push_back("mozc-dv");
640   EXPECT_TRUE(manager_->GetActiveIMEState()->ReplaceEnabledInputMethods(ids));
641   EXPECT_EQ(1, observer.input_method_changed_count_);
642   EXPECT_EQ(ImeIdFromEngineId(ids[0]),
643             manager_->GetActiveIMEState()->GetCurrentInputMethod().id());
644   EXPECT_EQ("us", keyboard_->last_layout_);
645   manager_->RemoveObserver(&observer);
646 }
647
648 TEST_F(InputMethodManagerImplTest, TestEnableUnknownIds) {
649   TestObserver observer;
650   InitComponentExtension();
651   manager_->AddObserver(&observer);
652   manager_->SetUISessionState(InputMethodManager::STATE_BROWSER_SCREEN);
653   std::vector<std::string> ids;
654   ids.push_back("xkb:tl::tlh");  // Klingon, which is not supported.
655   ids.push_back("unknown-super-cool-ime");
656   EXPECT_FALSE(manager_->GetActiveIMEState()->ReplaceEnabledInputMethods(ids));
657
658   // TODO(yusukes): Should we fall back to the hardware keyboard layout in this
659   // case?
660   EXPECT_EQ(0, observer.input_method_changed_count_);
661
662   manager_->RemoveObserver(&observer);
663 }
664
665 TEST_F(InputMethodManagerImplTest, TestEnableLayoutsThenLock) {
666   // For http://crbug.com/19655#c11 - (14).
667   TestObserver observer;
668   InitComponentExtension();
669   manager_->AddObserver(&observer);
670   manager_->SetUISessionState(InputMethodManager::STATE_BROWSER_SCREEN);
671   std::vector<std::string> ids;
672   ids.push_back(ImeIdFromEngineId("xkb:us::eng"));
673   ids.push_back(ImeIdFromEngineId("xkb:us:dvorak:eng"));
674   EXPECT_TRUE(manager_->GetActiveIMEState()->ReplaceEnabledInputMethods(ids));
675   EXPECT_EQ(2U, manager_->GetActiveIMEState()->GetNumActiveInputMethods());
676   EXPECT_EQ(1, observer.input_method_changed_count_);
677   EXPECT_EQ(ImeIdFromEngineId(ids[0]),
678             manager_->GetActiveIMEState()->GetCurrentInputMethod().id());
679   EXPECT_EQ("us", keyboard_->last_layout_);
680
681   // Switch to Dvorak.
682   manager_->GetActiveIMEState()->SwitchToNextInputMethod();
683   EXPECT_EQ(2, observer.input_method_changed_count_);
684   EXPECT_EQ(ImeIdFromEngineId(ids[1]),
685             manager_->GetActiveIMEState()->GetCurrentInputMethod().id());
686   EXPECT_EQ("us(dvorak)", keyboard_->last_layout_);
687
688   // Lock screen
689   scoped_refptr<input_method::InputMethodManager::State> saved_ime_state =
690       manager_->GetActiveIMEState();
691   manager_->SetState(saved_ime_state->Clone());
692   manager_->GetActiveIMEState()->EnableLockScreenLayouts();
693   manager_->SetUISessionState(InputMethodManager::STATE_LOCK_SCREEN);
694   EXPECT_EQ(2U, manager_->GetActiveIMEState()->GetNumActiveInputMethods());
695   EXPECT_EQ(ImeIdFromEngineId(ids[1]),  // still Dvorak
696             manager_->GetActiveIMEState()->GetCurrentInputMethod().id());
697   EXPECT_EQ("us(dvorak)", keyboard_->last_layout_);
698   // Switch back to Qwerty.
699   manager_->GetActiveIMEState()->SwitchToNextInputMethod();
700   EXPECT_EQ(ImeIdFromEngineId(ids[0]),
701             manager_->GetActiveIMEState()->GetCurrentInputMethod().id());
702   EXPECT_EQ("us", keyboard_->last_layout_);
703
704   // Unlock screen. The original state, Dvorak, is restored.
705   manager_->SetState(saved_ime_state);
706   manager_->SetUISessionState(InputMethodManager::STATE_BROWSER_SCREEN);
707   EXPECT_EQ(2U, manager_->GetActiveIMEState()->GetNumActiveInputMethods());
708   EXPECT_EQ(ImeIdFromEngineId(ids[1]),
709             manager_->GetActiveIMEState()->GetCurrentInputMethod().id());
710   EXPECT_EQ("us(dvorak)", keyboard_->last_layout_);
711
712   manager_->RemoveObserver(&observer);
713 }
714
715 TEST_F(InputMethodManagerImplTest, SwitchInputMethodTest) {
716   // For http://crbug.com/19655#c11 - (15).
717   TestObserver observer;
718   InitComponentExtension();
719   manager_->AddObserver(&observer);
720   manager_->SetUISessionState(InputMethodManager::STATE_BROWSER_SCREEN);
721   std::vector<std::string> ids;
722   ids.push_back(ImeIdFromEngineId("xkb:us:dvorak:eng"));
723   ids.push_back(ImeIdFromEngineId(kExt2Engine2Id));
724   ids.push_back(ImeIdFromEngineId(kExt2Engine1Id));
725   EXPECT_TRUE(manager_->GetActiveIMEState()->ReplaceEnabledInputMethods(ids));
726   EXPECT_EQ(3U, manager_->GetActiveIMEState()->GetNumActiveInputMethods());
727   EXPECT_EQ(1, observer.input_method_changed_count_);
728   EXPECT_EQ(ImeIdFromEngineId(ids[0]),
729             manager_->GetActiveIMEState()->GetCurrentInputMethod().id());
730   EXPECT_EQ("us(dvorak)", keyboard_->last_layout_);
731
732   // Switch to Mozc.
733   manager_->GetActiveIMEState()->SwitchToNextInputMethod();
734   EXPECT_EQ(2, observer.input_method_changed_count_);
735   EXPECT_EQ(ImeIdFromEngineId(ids[1]),
736             manager_->GetActiveIMEState()->GetCurrentInputMethod().id());
737   EXPECT_EQ("us(dvorak)", keyboard_->last_layout_);
738
739   // Lock screen
740   scoped_refptr<input_method::InputMethodManager::State> saved_ime_state =
741       manager_->GetActiveIMEState();
742   manager_->SetState(saved_ime_state->Clone());
743   manager_->GetActiveIMEState()->EnableLockScreenLayouts();
744   manager_->SetUISessionState(InputMethodManager::STATE_LOCK_SCREEN);
745   EXPECT_EQ(2U,
746             manager_->GetActiveIMEState()
747                 ->GetNumActiveInputMethods());  // Qwerty+Dvorak.
748   EXPECT_EQ(ImeIdFromEngineId("xkb:us:dvorak:eng"),
749             manager_->GetActiveIMEState()->GetCurrentInputMethod().id());
750   EXPECT_EQ("us(dvorak)", keyboard_->last_layout_);
751   manager_->GetActiveIMEState()->SwitchToNextInputMethod();
752   EXPECT_EQ(ImeIdFromEngineId("xkb:us::eng"),  // The hardware keyboard layout.
753             manager_->GetActiveIMEState()->GetCurrentInputMethod().id());
754   EXPECT_EQ("us", keyboard_->last_layout_);
755
756   // Unlock screen. The original state, pinyin-dv, is restored.
757   manager_->SetState(saved_ime_state);
758   manager_->SetUISessionState(InputMethodManager::STATE_BROWSER_SCREEN);
759   EXPECT_EQ(3U,
760             manager_->GetActiveIMEState()
761                 ->GetNumActiveInputMethods());  // Dvorak and 2 IMEs.
762   EXPECT_EQ(ImeIdFromEngineId(ids[1]),
763             manager_->GetActiveIMEState()->GetCurrentInputMethod().id());
764   EXPECT_EQ("us(dvorak)", keyboard_->last_layout_);
765
766   manager_->RemoveObserver(&observer);
767 }
768
769 TEST_F(InputMethodManagerImplTest, TestXkbSetting) {
770   EXPECT_EQ(0, keyboard_->set_current_keyboard_layout_by_name_count_);
771   // For http://crbug.com/19655#c11 - (8), step 7-11.
772   InitComponentExtension();
773   EXPECT_EQ(1, keyboard_->set_current_keyboard_layout_by_name_count_);
774   manager_->SetUISessionState(InputMethodManager::STATE_BROWSER_SCREEN);
775   std::vector<std::string> ids;
776   ids.push_back(ImeIdFromEngineId("xkb:us:dvorak:eng"));
777   ids.push_back(ImeIdFromEngineId("xkb:us:colemak:eng"));
778   ids.push_back(ImeIdFromEngineId(kNaclMozcJpId));
779   ids.push_back(ImeIdFromEngineId(kNaclMozcUsId));
780   EXPECT_TRUE(manager_->GetActiveIMEState()->ReplaceEnabledInputMethods(ids));
781   EXPECT_EQ(4U, manager_->GetActiveIMEState()->GetNumActiveInputMethods());
782   EXPECT_EQ(2, keyboard_->set_current_keyboard_layout_by_name_count_);
783   // See input_methods.txt for an expected XKB layout name.
784   EXPECT_EQ("us(dvorak)", keyboard_->last_layout_);
785   manager_->GetActiveIMEState()->SwitchToNextInputMethod();
786   EXPECT_EQ(3, keyboard_->set_current_keyboard_layout_by_name_count_);
787   EXPECT_EQ("us(colemak)", keyboard_->last_layout_);
788   manager_->GetActiveIMEState()->SwitchToNextInputMethod();
789   EXPECT_EQ(4, keyboard_->set_current_keyboard_layout_by_name_count_);
790   EXPECT_EQ("jp", keyboard_->last_layout_);
791   manager_->GetActiveIMEState()->SwitchToNextInputMethod();
792   EXPECT_EQ(5, keyboard_->set_current_keyboard_layout_by_name_count_);
793   EXPECT_EQ("us", keyboard_->last_layout_);
794   manager_->GetActiveIMEState()->SwitchToNextInputMethod();
795   EXPECT_EQ(6, keyboard_->set_current_keyboard_layout_by_name_count_);
796   EXPECT_EQ("us(dvorak)", keyboard_->last_layout_);
797   // Disable Dvorak.
798   ids.erase(ids.begin());
799   EXPECT_TRUE(manager_->GetActiveIMEState()->ReplaceEnabledInputMethods(ids));
800   EXPECT_EQ(3U, manager_->GetActiveIMEState()->GetNumActiveInputMethods());
801   EXPECT_EQ(7, keyboard_->set_current_keyboard_layout_by_name_count_);
802   EXPECT_EQ("us(colemak)", keyboard_->last_layout_);
803 }
804
805 TEST_F(InputMethodManagerImplTest, TestActivateInputMethodMenuItem) {
806   const std::string kKey = "key";
807   ash::ime::InputMethodMenuItemList menu_list;
808   menu_list.push_back(ash::ime::InputMethodMenuItem(
809       kKey, "label", false, false));
810   menu_manager_->SetCurrentInputMethodMenuItemList(menu_list);
811
812   manager_->ActivateInputMethodMenuItem(kKey);
813   EXPECT_EQ(kKey, mock_engine_handler_->last_activated_property());
814
815   // Key2 is not registered, so activated property should not be changed.
816   manager_->ActivateInputMethodMenuItem("key2");
817   EXPECT_EQ(kKey, mock_engine_handler_->last_activated_property());
818 }
819
820 TEST_F(InputMethodManagerImplTest, TestGetCurrentInputMethodProperties) {
821   InitComponentExtension();
822   EXPECT_TRUE(menu_manager_->GetCurrentInputMethodMenuItemList().empty());
823
824   manager_->SetUISessionState(InputMethodManager::STATE_BROWSER_SCREEN);
825   std::vector<std::string> ids;
826   ids.push_back(ImeIdFromEngineId("xkb:us::eng"));
827   ids.push_back(ImeIdFromEngineId(kNaclMozcUsId));
828   EXPECT_TRUE(manager_->GetActiveIMEState()->ReplaceEnabledInputMethods(ids));
829   EXPECT_EQ(2U, manager_->GetActiveIMEState()->GetNumActiveInputMethods());
830   EXPECT_TRUE(menu_manager_->GetCurrentInputMethodMenuItemList().empty());
831   manager_->GetActiveIMEState()->ChangeInputMethod(
832       ImeIdFromEngineId(kNaclMozcUsId), false /* show_message */);
833
834   ash::ime::InputMethodMenuItemList current_property_list;
835   current_property_list.push_back(ash::ime::InputMethodMenuItem(
836       "key", "label", false, false));
837   menu_manager_->SetCurrentInputMethodMenuItemList(current_property_list);
838
839   ASSERT_EQ(1U, menu_manager_->GetCurrentInputMethodMenuItemList().size());
840   EXPECT_EQ("key",
841             menu_manager_->GetCurrentInputMethodMenuItemList().at(0).key);
842
843   manager_->GetActiveIMEState()->ChangeInputMethod("xkb:us::eng",
844                                                    false /* show_message */);
845   EXPECT_TRUE(menu_manager_->GetCurrentInputMethodMenuItemList().empty());
846 }
847
848 TEST_F(InputMethodManagerImplTest, TestGetCurrentInputMethodPropertiesTwoImes) {
849   InitComponentExtension();
850   EXPECT_TRUE(menu_manager_->GetCurrentInputMethodMenuItemList().empty());
851
852   manager_->SetUISessionState(InputMethodManager::STATE_BROWSER_SCREEN);
853   std::vector<std::string> ids;
854   ids.push_back(ImeIdFromEngineId(kNaclMozcUsId));   // Japanese
855   ids.push_back(ImeIdFromEngineId(kExt2Engine1Id));  // T-Chinese
856   EXPECT_TRUE(manager_->GetActiveIMEState()->ReplaceEnabledInputMethods(ids));
857   EXPECT_EQ(2U, manager_->GetActiveIMEState()->GetNumActiveInputMethods());
858   EXPECT_TRUE(menu_manager_->GetCurrentInputMethodMenuItemList().empty());
859
860   ash::ime::InputMethodMenuItemList current_property_list;
861   current_property_list.push_back(ash::ime::InputMethodMenuItem("key-mozc",
862                                                                 "label",
863                                                                 false,
864                                                                 false));
865   menu_manager_->SetCurrentInputMethodMenuItemList(current_property_list);
866
867   ASSERT_EQ(1U, menu_manager_->GetCurrentInputMethodMenuItemList().size());
868   EXPECT_EQ("key-mozc",
869             menu_manager_->GetCurrentInputMethodMenuItemList().at(0).key);
870
871   manager_->GetActiveIMEState()->ChangeInputMethod(
872       ImeIdFromEngineId(kExt2Engine1Id), false /* show_message */);
873   // Since the IME is changed, the property for mozc Japanese should be hidden.
874   EXPECT_TRUE(menu_manager_->GetCurrentInputMethodMenuItemList().empty());
875
876   // Asynchronous property update signal from mozc-chewing.
877   current_property_list.clear();
878   current_property_list.push_back(ash::ime::InputMethodMenuItem(
879       "key-chewing", "label", false, false));
880   menu_manager_->SetCurrentInputMethodMenuItemList(current_property_list);
881   ASSERT_EQ(1U, menu_manager_->GetCurrentInputMethodMenuItemList().size());
882   EXPECT_EQ("key-chewing",
883             menu_manager_->GetCurrentInputMethodMenuItemList().at(0).key);
884 }
885
886 TEST_F(InputMethodManagerImplTest, TestNextInputMethod) {
887   TestObserver observer;
888   InitComponentExtension();
889   manager_->AddObserver(&observer);
890   std::vector<std::string> keyboard_layouts;
891   keyboard_layouts.push_back(ImeIdFromEngineId("xkb:us::eng"));
892   // For http://crbug.com/19655#c11 - (1)
893   manager_->GetActiveIMEState()->EnableLoginLayouts("en-US", keyboard_layouts);
894   EXPECT_EQ(5U, manager_->GetActiveIMEState()->GetNumActiveInputMethods());
895   EXPECT_EQ(ImeIdFromEngineId("xkb:us::eng"),
896             manager_->GetActiveIMEState()->GetCurrentInputMethod().id());
897   EXPECT_EQ("us", keyboard_->last_layout_);
898   manager_->GetActiveIMEState()->SwitchToNextInputMethod();
899   EXPECT_TRUE(observer.last_show_message_);
900   EXPECT_EQ(ImeIdFromEngineId("xkb:us:intl:eng"),
901             manager_->GetActiveIMEState()->GetCurrentInputMethod().id());
902   EXPECT_EQ("us(intl)", keyboard_->last_layout_);
903   manager_->GetActiveIMEState()->SwitchToNextInputMethod();
904   EXPECT_TRUE(observer.last_show_message_);
905   EXPECT_EQ(ImeIdFromEngineId("xkb:us:altgr-intl:eng"),
906             manager_->GetActiveIMEState()->GetCurrentInputMethod().id());
907   EXPECT_EQ("us(altgr-intl)", keyboard_->last_layout_);
908   manager_->GetActiveIMEState()->SwitchToNextInputMethod();
909   EXPECT_TRUE(observer.last_show_message_);
910   EXPECT_EQ(ImeIdFromEngineId("xkb:us:dvorak:eng"),
911             manager_->GetActiveIMEState()->GetCurrentInputMethod().id());
912   EXPECT_EQ("us(dvorak)", keyboard_->last_layout_);
913   manager_->GetActiveIMEState()->SwitchToNextInputMethod();
914   EXPECT_TRUE(observer.last_show_message_);
915   EXPECT_EQ(ImeIdFromEngineId("xkb:us:colemak:eng"),
916             manager_->GetActiveIMEState()->GetCurrentInputMethod().id());
917   EXPECT_EQ("us(colemak)", keyboard_->last_layout_);
918   manager_->GetActiveIMEState()->SwitchToNextInputMethod();
919   EXPECT_TRUE(observer.last_show_message_);
920   EXPECT_EQ(ImeIdFromEngineId("xkb:us::eng"),
921             manager_->GetActiveIMEState()->GetCurrentInputMethod().id());
922   EXPECT_EQ("us", keyboard_->last_layout_);
923
924   manager_->RemoveObserver(&observer);
925 }
926
927 TEST_F(InputMethodManagerImplTest, TestPreviousInputMethod) {
928   TestObserver observer;
929   InitComponentExtension();
930   manager_->AddObserver(&observer);
931
932   ui::Accelerator keydown_accelerator(ui::VKEY_SPACE, ui::EF_CONTROL_DOWN);
933   keydown_accelerator.set_type(ui::ET_KEY_PRESSED);
934   ui::Accelerator keyup_accelerator(ui::VKEY_SPACE, ui::EF_CONTROL_DOWN);
935   keyup_accelerator.set_type(ui::ET_KEY_RELEASED);
936
937   std::vector<std::string> keyboard_layouts;
938   keyboard_layouts.push_back(ImeIdFromEngineId("xkb:us::eng"));
939   manager_->GetActiveIMEState()->EnableLoginLayouts("en-US", keyboard_layouts);
940   EXPECT_EQ(5U, manager_->GetActiveIMEState()->GetNumActiveInputMethods());
941   EXPECT_EQ(ImeIdFromEngineId("xkb:us::eng"),
942             manager_->GetActiveIMEState()->GetCurrentInputMethod().id());
943   EXPECT_EQ("us", keyboard_->last_layout_);
944   EXPECT_TRUE(manager_->GetActiveIMEState()->SwitchToNextInputMethod());
945   EXPECT_TRUE(observer.last_show_message_);
946   EXPECT_EQ(ImeIdFromEngineId("xkb:us:intl:eng"),
947             manager_->GetActiveIMEState()->GetCurrentInputMethod().id());
948   EXPECT_EQ("us(intl)", keyboard_->last_layout_);
949   EXPECT_TRUE(manager_->GetActiveIMEState()->SwitchToPreviousInputMethod(
950       keydown_accelerator));
951   EXPECT_TRUE(manager_->GetActiveIMEState()->SwitchToPreviousInputMethod(
952       keyup_accelerator));
953   EXPECT_TRUE(observer.last_show_message_);
954   EXPECT_EQ(ImeIdFromEngineId("xkb:us::eng"),
955             manager_->GetActiveIMEState()->GetCurrentInputMethod().id());
956   EXPECT_EQ("us", keyboard_->last_layout_);
957   EXPECT_TRUE(manager_->GetActiveIMEState()->SwitchToPreviousInputMethod(
958       keydown_accelerator));
959   EXPECT_TRUE(manager_->GetActiveIMEState()->SwitchToPreviousInputMethod(
960       keyup_accelerator));
961   EXPECT_TRUE(observer.last_show_message_);
962   EXPECT_EQ(ImeIdFromEngineId("xkb:us:intl:eng"),
963             manager_->GetActiveIMEState()->GetCurrentInputMethod().id());
964   EXPECT_EQ("us(intl)", keyboard_->last_layout_);
965   EXPECT_TRUE(manager_->GetActiveIMEState()->SwitchToPreviousInputMethod(
966       keydown_accelerator));
967   EXPECT_TRUE(manager_->GetActiveIMEState()->SwitchToPreviousInputMethod(
968       keyup_accelerator));
969   EXPECT_TRUE(observer.last_show_message_);
970   EXPECT_EQ(ImeIdFromEngineId("xkb:us::eng"),
971             manager_->GetActiveIMEState()->GetCurrentInputMethod().id());
972   EXPECT_EQ("us", keyboard_->last_layout_);
973   EXPECT_TRUE(manager_->GetActiveIMEState()->SwitchToNextInputMethod());
974   EXPECT_TRUE(observer.last_show_message_);
975   EXPECT_EQ(ImeIdFromEngineId("xkb:us:intl:eng"),
976             manager_->GetActiveIMEState()->GetCurrentInputMethod().id());
977   EXPECT_EQ("us(intl)", keyboard_->last_layout_);
978   EXPECT_TRUE(manager_->GetActiveIMEState()->SwitchToNextInputMethod());
979   EXPECT_TRUE(observer.last_show_message_);
980   EXPECT_EQ(ImeIdFromEngineId("xkb:us:altgr-intl:eng"),
981             manager_->GetActiveIMEState()->GetCurrentInputMethod().id());
982   EXPECT_EQ("us(altgr-intl)", keyboard_->last_layout_);
983   EXPECT_TRUE(manager_->GetActiveIMEState()->SwitchToPreviousInputMethod(
984       keydown_accelerator));
985   EXPECT_TRUE(manager_->GetActiveIMEState()->SwitchToPreviousInputMethod(
986       keyup_accelerator));
987   EXPECT_TRUE(observer.last_show_message_);
988   EXPECT_EQ(ImeIdFromEngineId("xkb:us:intl:eng"),
989             manager_->GetActiveIMEState()->GetCurrentInputMethod().id());
990   EXPECT_EQ("us(intl)", keyboard_->last_layout_);
991   EXPECT_TRUE(manager_->GetActiveIMEState()->SwitchToPreviousInputMethod(
992       keydown_accelerator));
993   EXPECT_TRUE(manager_->GetActiveIMEState()->SwitchToPreviousInputMethod(
994       keyup_accelerator));
995   EXPECT_TRUE(observer.last_show_message_);
996   EXPECT_EQ(ImeIdFromEngineId("xkb:us:altgr-intl:eng"),
997             manager_->GetActiveIMEState()->GetCurrentInputMethod().id());
998   EXPECT_EQ("us(altgr-intl)", keyboard_->last_layout_);
999
1000   manager_->RemoveObserver(&observer);
1001 }
1002
1003 TEST_F(InputMethodManagerImplTest,
1004        TestSwitchToPreviousInputMethodForOneActiveInputMethod) {
1005   TestObserver observer;
1006   InitComponentExtension();
1007   manager_->AddObserver(&observer);
1008
1009   ui::Accelerator keydown_accelerator(ui::VKEY_SPACE, ui::EF_CONTROL_DOWN);
1010   keydown_accelerator.set_type(ui::ET_KEY_PRESSED);
1011   ui::Accelerator keyup_accelerator(ui::VKEY_SPACE, ui::EF_CONTROL_DOWN);
1012   keyup_accelerator.set_type(ui::ET_KEY_RELEASED);
1013
1014   std::vector<std::string> ids;
1015   ids.push_back(ImeIdFromEngineId("xkb:us:dvorak:eng"));
1016   EXPECT_TRUE(manager_->GetActiveIMEState()->ReplaceEnabledInputMethods(ids));
1017   EXPECT_EQ(1U, manager_->GetActiveIMEState()->GetNumActiveInputMethods());
1018
1019   // Ctrl+Space accelerator should not be consumed if there is only one active
1020   // input method.
1021   EXPECT_FALSE(manager_->GetActiveIMEState()->SwitchToPreviousInputMethod(
1022       keydown_accelerator));
1023   EXPECT_FALSE(manager_->GetActiveIMEState()->SwitchToPreviousInputMethod(
1024       keyup_accelerator));
1025
1026   manager_->RemoveObserver(&observer);
1027 }
1028
1029 TEST_F(InputMethodManagerImplTest, TestSwitchInputMethodWithUsLayouts) {
1030   std::string expect_id = ImeIdFromEngineId("xkb:us::eng");
1031   TestObserver observer;
1032   InitComponentExtension();
1033   manager_->AddObserver(&observer);
1034   std::vector<std::string> keyboard_layouts;
1035   keyboard_layouts.push_back(ImeIdFromEngineId("xkb:us::eng"));
1036   manager_->GetActiveIMEState()->EnableLoginLayouts("en-US", keyboard_layouts);
1037   EXPECT_EQ(5U, manager_->GetActiveIMEState()->GetNumActiveInputMethods());
1038   EXPECT_EQ(expect_id,
1039             manager_->GetActiveIMEState()->GetCurrentInputMethod().id());
1040   EXPECT_EQ("us", keyboard_->last_layout_);
1041
1042   // Henkan, Muhenkan, ZenkakuHankaku should be ignored when no Japanese IMEs
1043   // and keyboards are enabled.
1044   EXPECT_FALSE(manager_->GetActiveIMEState()->SwitchInputMethod(
1045       ui::Accelerator(ui::VKEY_CONVERT, ui::EF_NONE)));
1046   EXPECT_FALSE(observer.last_show_message_);
1047   EXPECT_EQ(expect_id,
1048             manager_->GetActiveIMEState()->GetCurrentInputMethod().id());
1049   EXPECT_EQ("us", keyboard_->last_layout_);
1050   EXPECT_FALSE(manager_->GetActiveIMEState()->SwitchInputMethod(
1051       ui::Accelerator(ui::VKEY_NONCONVERT, ui::EF_NONE)));
1052   EXPECT_EQ(expect_id,
1053             manager_->GetActiveIMEState()->GetCurrentInputMethod().id());
1054   EXPECT_EQ("us", keyboard_->last_layout_);
1055   EXPECT_FALSE(manager_->GetActiveIMEState()->SwitchInputMethod(
1056       ui::Accelerator(ui::VKEY_DBE_SBCSCHAR, ui::EF_NONE)));
1057   EXPECT_EQ(expect_id,
1058             manager_->GetActiveIMEState()->GetCurrentInputMethod().id());
1059   EXPECT_EQ("us", keyboard_->last_layout_);
1060   EXPECT_FALSE(manager_->GetActiveIMEState()->SwitchInputMethod(
1061       ui::Accelerator(ui::VKEY_DBE_DBCSCHAR, ui::EF_NONE)));
1062   EXPECT_EQ(expect_id,
1063             manager_->GetActiveIMEState()->GetCurrentInputMethod().id());
1064   EXPECT_EQ("us", keyboard_->last_layout_);
1065
1066   manager_->RemoveObserver(&observer);
1067 }
1068
1069 TEST_F(InputMethodManagerImplTest, TestSwitchInputMethodWithJpLayout) {
1070   // Enable "xkb:jp::jpn" and press Muhenkan/ZenkakuHankaku.
1071   InitComponentExtension();
1072
1073   ui::Accelerator keydown_accelerator(ui::VKEY_SPACE, ui::EF_CONTROL_DOWN);
1074   keydown_accelerator.set_type(ui::ET_KEY_PRESSED);
1075   ui::Accelerator keyup_accelerator(ui::VKEY_SPACE, ui::EF_CONTROL_DOWN);
1076   keyup_accelerator.set_type(ui::ET_KEY_RELEASED);
1077
1078   std::vector<std::string> keyboard_layouts;
1079   keyboard_layouts.push_back(ImeIdFromEngineId("xkb:us::eng"));
1080   manager_->GetActiveIMEState()->EnableLoginLayouts("ja", keyboard_layouts);
1081   EXPECT_EQ(2U, manager_->GetActiveIMEState()->GetNumActiveInputMethods());
1082   EXPECT_EQ(ImeIdFromEngineId("xkb:us::eng"),
1083             manager_->GetActiveIMEState()->GetCurrentInputMethod().id());
1084   EXPECT_EQ("us", keyboard_->last_layout_);
1085   EXPECT_TRUE(manager_->GetActiveIMEState()->SwitchInputMethod(
1086       ui::Accelerator(ui::VKEY_NONCONVERT, ui::EF_NONE)));
1087   EXPECT_EQ(ImeIdFromEngineId("xkb:jp::jpn"),
1088             manager_->GetActiveIMEState()->GetCurrentInputMethod().id());
1089   EXPECT_EQ("jp", keyboard_->last_layout_);
1090   EXPECT_TRUE(manager_->GetActiveIMEState()->SwitchToPreviousInputMethod(
1091       keydown_accelerator));
1092   EXPECT_TRUE(manager_->GetActiveIMEState()->SwitchToPreviousInputMethod(
1093       keyup_accelerator));
1094   EXPECT_EQ(ImeIdFromEngineId("xkb:us::eng"),
1095             manager_->GetActiveIMEState()->GetCurrentInputMethod().id());
1096   EXPECT_EQ("us", keyboard_->last_layout_);
1097   EXPECT_TRUE(manager_->GetActiveIMEState()->SwitchInputMethod(
1098       ui::Accelerator(ui::VKEY_DBE_SBCSCHAR, ui::EF_NONE)));
1099   EXPECT_EQ(ImeIdFromEngineId("xkb:jp::jpn"),
1100             manager_->GetActiveIMEState()->GetCurrentInputMethod().id());
1101   EXPECT_EQ("jp", keyboard_->last_layout_);
1102   EXPECT_TRUE(manager_->GetActiveIMEState()->SwitchToPreviousInputMethod(
1103       keydown_accelerator));
1104   EXPECT_TRUE(manager_->GetActiveIMEState()->SwitchToPreviousInputMethod(
1105       keyup_accelerator));
1106   EXPECT_EQ(ImeIdFromEngineId("xkb:us::eng"),
1107             manager_->GetActiveIMEState()->GetCurrentInputMethod().id());
1108   EXPECT_EQ("us", keyboard_->last_layout_);
1109   EXPECT_TRUE(manager_->GetActiveIMEState()->SwitchInputMethod(
1110       ui::Accelerator(ui::VKEY_DBE_DBCSCHAR, ui::EF_NONE)));
1111   EXPECT_EQ(ImeIdFromEngineId("xkb:jp::jpn"),
1112             manager_->GetActiveIMEState()->GetCurrentInputMethod().id());
1113   EXPECT_EQ("jp", keyboard_->last_layout_);
1114 }
1115
1116 TEST_F(InputMethodManagerImplTest, TestSwitchInputMethodWithJpIme) {
1117   InitComponentExtension();
1118   manager_->SetUISessionState(InputMethodManager::STATE_BROWSER_SCREEN);
1119   std::vector<std::string> ids;
1120   ids.push_back(ImeIdFromEngineId("xkb:jp::jpn"));
1121   ids.push_back(ImeIdFromEngineId(kNaclMozcJpId));
1122   EXPECT_TRUE(manager_->GetActiveIMEState()->ReplaceEnabledInputMethods(ids));
1123   EXPECT_EQ(ImeIdFromEngineId("xkb:jp::jpn"),
1124             manager_->GetActiveIMEState()->GetCurrentInputMethod().id());
1125   EXPECT_EQ("jp", keyboard_->last_layout_);
1126   EXPECT_TRUE(manager_->GetActiveIMEState()->SwitchInputMethod(
1127       ui::Accelerator(ui::VKEY_DBE_DBCSCHAR, ui::EF_NONE)));
1128   EXPECT_EQ(ImeIdFromEngineId(kNaclMozcJpId),
1129             manager_->GetActiveIMEState()->GetCurrentInputMethod().id());
1130   EXPECT_EQ("jp", keyboard_->last_layout_);
1131   EXPECT_TRUE(manager_->GetActiveIMEState()->SwitchInputMethod(
1132       ui::Accelerator(ui::VKEY_DBE_DBCSCHAR, ui::EF_NONE)));
1133   EXPECT_EQ(ImeIdFromEngineId("xkb:jp::jpn"),
1134             manager_->GetActiveIMEState()->GetCurrentInputMethod().id());
1135   EXPECT_EQ("jp", keyboard_->last_layout_);
1136   EXPECT_TRUE(manager_->GetActiveIMEState()->SwitchInputMethod(
1137       ui::Accelerator(ui::VKEY_CONVERT, ui::EF_NONE)));
1138   EXPECT_EQ(ImeIdFromEngineId(kNaclMozcJpId),
1139             manager_->GetActiveIMEState()->GetCurrentInputMethod().id());
1140   EXPECT_EQ("jp", keyboard_->last_layout_);
1141   EXPECT_TRUE(manager_->GetActiveIMEState()->SwitchInputMethod(
1142       ui::Accelerator(ui::VKEY_CONVERT, ui::EF_NONE)));
1143   EXPECT_EQ(ImeIdFromEngineId(kNaclMozcJpId),
1144             manager_->GetActiveIMEState()->GetCurrentInputMethod().id());
1145   EXPECT_EQ("jp", keyboard_->last_layout_);
1146   EXPECT_TRUE(manager_->GetActiveIMEState()->SwitchInputMethod(
1147       ui::Accelerator(ui::VKEY_NONCONVERT, ui::EF_NONE)));
1148   EXPECT_EQ(ImeIdFromEngineId("xkb:jp::jpn"),
1149             manager_->GetActiveIMEState()->GetCurrentInputMethod().id());
1150   EXPECT_EQ("jp", keyboard_->last_layout_);
1151   EXPECT_TRUE(manager_->GetActiveIMEState()->SwitchInputMethod(
1152       ui::Accelerator(ui::VKEY_NONCONVERT, ui::EF_NONE)));
1153   EXPECT_EQ(ImeIdFromEngineId("xkb:jp::jpn"),
1154             manager_->GetActiveIMEState()->GetCurrentInputMethod().id());
1155   EXPECT_EQ("jp", keyboard_->last_layout_);
1156
1157   // Add Dvorak.
1158   ids.push_back(ImeIdFromEngineId("xkb:us:dvorak:eng"));
1159   EXPECT_TRUE(manager_->GetActiveIMEState()->ReplaceEnabledInputMethods(ids));
1160   EXPECT_EQ(ImeIdFromEngineId("xkb:jp::jpn"),
1161             manager_->GetActiveIMEState()->GetCurrentInputMethod().id());
1162   EXPECT_EQ("jp", keyboard_->last_layout_);
1163   EXPECT_TRUE(manager_->GetActiveIMEState()->SwitchInputMethod(
1164       ui::Accelerator(ui::VKEY_DBE_SBCSCHAR, ui::EF_NONE)));
1165   EXPECT_EQ(ImeIdFromEngineId(kNaclMozcJpId),
1166             manager_->GetActiveIMEState()->GetCurrentInputMethod().id());
1167   EXPECT_EQ("jp", keyboard_->last_layout_);
1168   EXPECT_TRUE(manager_->GetActiveIMEState()->SwitchInputMethod(
1169       ui::Accelerator(ui::VKEY_DBE_SBCSCHAR, ui::EF_NONE)));
1170   EXPECT_EQ(ImeIdFromEngineId("xkb:jp::jpn"),
1171             manager_->GetActiveIMEState()->GetCurrentInputMethod().id());
1172   EXPECT_EQ("jp", keyboard_->last_layout_);
1173 }
1174
1175 TEST_F(InputMethodManagerImplTest, TestAddRemoveExtensionInputMethods) {
1176   TestObserver observer;
1177   InitComponentExtension();
1178   manager_->AddObserver(&observer);
1179   manager_->SetUISessionState(InputMethodManager::STATE_BROWSER_SCREEN);
1180   std::vector<std::string> ids;
1181   ids.push_back(ImeIdFromEngineId("xkb:us:dvorak:eng"));
1182   EXPECT_TRUE(manager_->GetActiveIMEState()->ReplaceEnabledInputMethods(ids));
1183   EXPECT_EQ(1U, manager_->GetActiveIMEState()->GetNumActiveInputMethods());
1184   EXPECT_EQ(1, observer.input_method_changed_count_);
1185   EXPECT_EQ(ImeIdFromEngineId(ids[0]),
1186             manager_->GetActiveIMEState()->GetCurrentInputMethod().id());
1187   EXPECT_EQ("us(dvorak)", keyboard_->last_layout_);
1188
1189   // Add two Extension IMEs.
1190   std::vector<std::string> layouts;
1191   layouts.push_back("us");
1192   std::vector<std::string> languages;
1193   languages.push_back("en-US");
1194
1195   const std::string ext1_id =
1196       extension_ime_util::GetInputMethodID(kExtensionId1, "engine_id");
1197   const InputMethodDescriptor descriptor1(ext1_id,
1198                                           "deadbeef input method",
1199                                           "DB",
1200                                           layouts,
1201                                           languages,
1202                                           false,  // is_login_keyboard
1203                                           GURL(),
1204                                           GURL());
1205   MockInputMethodEngine engine;
1206   InputMethodDescriptors descriptors;
1207   descriptors.push_back(descriptor1);
1208   manager_->GetActiveIMEState()->AddInputMethodExtension(
1209       kExtensionId1, descriptors, &engine);
1210
1211   // Extension IMEs are not enabled by default.
1212   EXPECT_EQ(1U, manager_->GetActiveIMEState()->GetNumActiveInputMethods());
1213
1214   std::vector<std::string> extension_ime_ids;
1215   extension_ime_ids.push_back(ext1_id);
1216   manager_->GetActiveIMEState()->SetEnabledExtensionImes(&extension_ime_ids);
1217   EXPECT_EQ(2U, manager_->GetActiveIMEState()->GetNumActiveInputMethods());
1218
1219   {
1220     scoped_ptr<InputMethodDescriptors> methods(
1221         manager_->GetActiveIMEState()->GetActiveInputMethods());
1222     ASSERT_EQ(2U, methods->size());
1223     // Ext IMEs should be at the end of the list.
1224     EXPECT_EQ(ext1_id, methods->at(1).id());
1225   }
1226
1227   const std::string ext2_id =
1228       extension_ime_util::GetInputMethodID(kExtensionId2, "engine_id");
1229   const InputMethodDescriptor descriptor2(ext2_id,
1230                                           "cafebabe input method",
1231                                           "CB",
1232                                           layouts,
1233                                           languages,
1234                                           false,  // is_login_keyboard
1235                                           GURL(),
1236                                           GURL());
1237   descriptors.clear();
1238   descriptors.push_back(descriptor2);
1239   MockInputMethodEngine engine2;
1240   manager_->GetActiveIMEState()->AddInputMethodExtension(
1241       kExtensionId2, descriptors, &engine2);
1242   EXPECT_EQ(2U, manager_->GetActiveIMEState()->GetNumActiveInputMethods());
1243
1244   extension_ime_ids.push_back(ext2_id);
1245   manager_->GetActiveIMEState()->SetEnabledExtensionImes(&extension_ime_ids);
1246   EXPECT_EQ(3U, manager_->GetActiveIMEState()->GetNumActiveInputMethods());
1247   {
1248     scoped_ptr<InputMethodDescriptors> methods(
1249         manager_->GetActiveIMEState()->GetActiveInputMethods());
1250     ASSERT_EQ(3U, methods->size());
1251     // Ext IMEs should be at the end of the list.
1252     EXPECT_EQ(ext1_id, methods->at(1).id());
1253     EXPECT_EQ(ext2_id, methods->at(2).id());
1254   }
1255
1256   // Remove them.
1257   manager_->GetActiveIMEState()->RemoveInputMethodExtension(kExtensionId1);
1258   EXPECT_EQ(2U, manager_->GetActiveIMEState()->GetNumActiveInputMethods());
1259   manager_->GetActiveIMEState()->RemoveInputMethodExtension(kExtensionId2);
1260   EXPECT_EQ(1U, manager_->GetActiveIMEState()->GetNumActiveInputMethods());
1261 }
1262
1263 TEST_F(InputMethodManagerImplTest, TestAddExtensionInputThenLockScreen) {
1264   TestObserver observer;
1265   InitComponentExtension();
1266   manager_->AddObserver(&observer);
1267   manager_->SetUISessionState(InputMethodManager::STATE_BROWSER_SCREEN);
1268   std::vector<std::string> ids;
1269   ids.push_back(ImeIdFromEngineId("xkb:us::eng"));
1270   EXPECT_TRUE(manager_->GetActiveIMEState()->ReplaceEnabledInputMethods(ids));
1271   EXPECT_EQ(1U, manager_->GetActiveIMEState()->GetNumActiveInputMethods());
1272   EXPECT_EQ(1, observer.input_method_changed_count_);
1273   EXPECT_EQ(ImeIdFromEngineId(ids[0]),
1274             manager_->GetActiveIMEState()->GetCurrentInputMethod().id());
1275   EXPECT_EQ("us", keyboard_->last_layout_);
1276
1277   // Add an Extension IME.
1278   std::vector<std::string> layouts;
1279   layouts.push_back("us(dvorak)");
1280   std::vector<std::string> languages;
1281   languages.push_back("en-US");
1282
1283   const std::string ext_id =
1284       extension_ime_util::GetInputMethodID(kExtensionId1, "engine_id");
1285   const InputMethodDescriptor descriptor(ext_id,
1286                                          "deadbeef input method",
1287                                          "DB",
1288                                          layouts,
1289                                          languages,
1290                                          false,  // is_login_keyboard
1291                                          GURL(),
1292                                          GURL());
1293   MockInputMethodEngine engine;
1294   InputMethodDescriptors descriptors;
1295   descriptors.push_back(descriptor);
1296   manager_->GetActiveIMEState()->AddInputMethodExtension(
1297       kExtensionId1, descriptors, &engine);
1298
1299   // Extension IME is not enabled by default.
1300   EXPECT_EQ(1U, manager_->GetActiveIMEState()->GetNumActiveInputMethods());
1301   EXPECT_EQ(1, observer.input_method_changed_count_);
1302
1303   std::vector<std::string> extension_ime_ids;
1304   extension_ime_ids.push_back(ext_id);
1305   manager_->GetActiveIMEState()->SetEnabledExtensionImes(&extension_ime_ids);
1306   EXPECT_EQ(2U, manager_->GetActiveIMEState()->GetNumActiveInputMethods());
1307
1308   // Switch to the IME.
1309   manager_->GetActiveIMEState()->SwitchToNextInputMethod();
1310   EXPECT_EQ(3, observer.input_method_changed_count_);
1311   EXPECT_EQ(ext_id,
1312             manager_->GetActiveIMEState()->GetCurrentInputMethod().id());
1313   EXPECT_EQ("us(dvorak)", keyboard_->last_layout_);
1314
1315   // Lock the screen. This is for crosbug.com/27049.
1316   scoped_refptr<input_method::InputMethodManager::State> saved_ime_state =
1317       manager_->GetActiveIMEState();
1318   manager_->SetState(saved_ime_state->Clone());
1319   manager_->GetActiveIMEState()->EnableLockScreenLayouts();
1320   manager_->SetUISessionState(InputMethodManager::STATE_LOCK_SCREEN);
1321   EXPECT_EQ(1U,
1322             manager_->GetActiveIMEState()
1323                 ->GetNumActiveInputMethods());  // Qwerty. No Ext. IME
1324   EXPECT_EQ(ImeIdFromEngineId("xkb:us::eng"),
1325             manager_->GetActiveIMEState()->GetCurrentInputMethod().id());
1326   EXPECT_EQ("us", keyboard_->last_layout_);
1327
1328   // Unlock the screen.
1329   manager_->SetState(saved_ime_state);
1330   manager_->SetUISessionState(InputMethodManager::STATE_BROWSER_SCREEN);
1331   EXPECT_EQ(2U, manager_->GetActiveIMEState()->GetNumActiveInputMethods());
1332   EXPECT_EQ(ext_id,
1333             manager_->GetActiveIMEState()->GetCurrentInputMethod().id());
1334   EXPECT_EQ("us(dvorak)", keyboard_->last_layout_);
1335   {
1336     // This is for crosbug.com/27052.
1337     scoped_ptr<InputMethodDescriptors> methods(
1338         manager_->GetActiveIMEState()->GetActiveInputMethods());
1339     ASSERT_EQ(2U, methods->size());
1340     // Ext. IMEs should be at the end of the list.
1341     EXPECT_EQ(ext_id, methods->at(1).id());
1342   }
1343   manager_->RemoveObserver(&observer);
1344 }
1345
1346 TEST_F(InputMethodManagerImplTest,
1347        ChangeInputMethod_ComponenteExtensionOneIME) {
1348   InitComponentExtension();
1349   manager_->SetUISessionState(InputMethodManager::STATE_BROWSER_SCREEN);
1350   const std::string ext_id = extension_ime_util::GetComponentInputMethodID(
1351       ime_list_[1].id,
1352       ime_list_[1].engines[0].engine_id);
1353   std::vector<std::string> ids;
1354   ids.push_back(ext_id);
1355   EXPECT_TRUE(manager_->GetActiveIMEState()->ReplaceEnabledInputMethods(ids));
1356   EXPECT_EQ(1U, manager_->GetActiveIMEState()->GetNumActiveInputMethods());
1357   EXPECT_EQ(ext_id,
1358             manager_->GetActiveIMEState()->GetCurrentInputMethod().id());
1359 }
1360
1361 TEST_F(InputMethodManagerImplTest,
1362        ChangeInputMethod_ComponenteExtensionTwoIME) {
1363   InitComponentExtension();
1364   manager_->SetUISessionState(InputMethodManager::STATE_BROWSER_SCREEN);
1365   const std::string ext_id1 = extension_ime_util::GetComponentInputMethodID(
1366       ime_list_[1].id,
1367       ime_list_[1].engines[0].engine_id);
1368   const std::string ext_id2 = extension_ime_util::GetComponentInputMethodID(
1369       ime_list_[2].id,
1370       ime_list_[2].engines[0].engine_id);
1371   std::vector<std::string> ids;
1372   ids.push_back(ext_id1);
1373   ids.push_back(ext_id2);
1374   EXPECT_TRUE(manager_->GetActiveIMEState()->ReplaceEnabledInputMethods(ids));
1375   EXPECT_EQ(2U, manager_->GetActiveIMEState()->GetNumActiveInputMethods());
1376   EXPECT_EQ(ext_id1,
1377             manager_->GetActiveIMEState()->GetCurrentInputMethod().id());
1378   manager_->GetActiveIMEState()->ChangeInputMethod(ext_id2,
1379                                                    false /* show_message */);
1380   EXPECT_EQ(ext_id2,
1381             manager_->GetActiveIMEState()->GetCurrentInputMethod().id());
1382 }
1383
1384 TEST_F(InputMethodManagerImplTest, MigrateInputMethodTest) {
1385   std::vector<std::string> input_method_ids;
1386   input_method_ids.push_back("xkb:us::eng");
1387   input_method_ids.push_back("xkb:fr::fra");
1388   input_method_ids.push_back(ImeIdFromEngineId("xkb:us::eng"));
1389   input_method_ids.push_back("xkb:fr::fra");
1390   input_method_ids.push_back(ImeIdFromEngineId("xkb:us::eng"));
1391   input_method_ids.push_back("_comp_ime_asdf_pinyin");
1392   input_method_ids.push_back(ImeIdFromEngineId(kPinyinImeId));
1393
1394   manager_->MigrateInputMethods(&input_method_ids);
1395
1396   ASSERT_EQ(4U, input_method_ids.size());
1397
1398   EXPECT_EQ(ImeIdFromEngineId("xkb:us::eng"), input_method_ids[0]);
1399   EXPECT_EQ(ImeIdFromEngineId("xkb:fr::fra"), input_method_ids[1]);
1400   EXPECT_EQ("_comp_ime_asdf_pinyin", input_method_ids[2]);
1401   EXPECT_EQ(ImeIdFromEngineId("zh-t-i0-pinyin"), input_method_ids[3]);
1402 }
1403
1404 }  // namespace input_method
1405 }  // namespace chromeos