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