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