input_method_manager_impl.cc revision a02191e04bc25c4935f804f2c080ae28663d096d
15821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Copyright (c) 2012 The Chromium Authors. All rights reserved.
25821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be
35821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// found in the LICENSE file.
45821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
55821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/browser/chromeos/input_method/input_method_manager_impl.h"
65821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
75821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <algorithm>  // std::find
85821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
9a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)#include "ash/ime/input_method_menu_item.h"
10a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)#include "ash/ime/input_method_menu_manager.h"
115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/basictypes.h"
12c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)#include "base/bind.h"
13c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)#include "base/location.h"
145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/memory/scoped_ptr.h"
15424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)#include "base/prefs/pref_service.h"
165e3f23d412006dc4db4e659864679f29341e113fTorne (Richard Coles)#include "base/strings/string_util.h"
175e3f23d412006dc4db4e659864679f29341e113fTorne (Richard Coles)#include "base/strings/stringprintf.h"
185d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#include "base/sys_info.h"
19424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)#include "chrome/browser/browser_process.h"
205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/browser/chromeos/input_method/candidate_window_controller.h"
21c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)#include "chrome/browser/chromeos/input_method/component_extension_ime_manager_impl.h"
22a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)#include "chrome/browser/chromeos/input_method/input_method_engine.h"
235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/browser/chromeos/language_preferences.h"
24a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch#include "chrome/browser/profiles/profile_manager.h"
25c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)#include "chromeos/ime/component_extension_ime_manager.h"
26c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)#include "chromeos/ime/extension_ime_util.h"
27a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch#include "chromeos/ime/fake_ime_keyboard.h"
28a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch#include "chromeos/ime/ime_keyboard.h"
292a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "chromeos/ime/input_method_delegate.h"
30ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch#include "third_party/icu/source/common/unicode/uloc.h"
315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "ui/base/accelerators/accelerator.h"
325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)namespace chromeos {
345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)namespace input_method {
355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)namespace {
375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
38c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)const char nacl_mozc_jp_id[] =
39c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    "_comp_ime_fpfbhcjppmaeaijcidgiibchfbnhbeljnacl_mozc_jp";
40c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool Contains(const std::vector<std::string>& container,
425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)              const std::string& value) {
435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return std::find(container.begin(), container.end(), value) !=
445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      container.end();
455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}  // namespace
485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
49424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)bool InputMethodManagerImpl::IsLoginKeyboard(
50a3f7b4e666c476898878fa745f637129375cd889Ben Murdoch    const std::string& layout) const {
515d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  return util_.IsLoginKeyboard(layout);
52a3f7b4e666c476898878fa745f637129375cd889Ben Murdoch}
53a3f7b4e666c476898878fa745f637129375cd889Ben Murdoch
54a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)bool InputMethodManagerImpl::MigrateXkbInputMethods(
55a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    std::vector<std::string>* input_method_ids) {
56a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  return util_.MigrateXkbInputMethods(input_method_ids);
57a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)}
58a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
592a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)InputMethodManagerImpl::InputMethodManagerImpl(
602a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    scoped_ptr<InputMethodDelegate> delegate)
612a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    : delegate_(delegate.Pass()),
622a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      state_(STATE_LOGIN_SCREEN),
63c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      util_(delegate_.get(), GetSupportedInputMethods()),
64c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      component_extension_ime_manager_(new ComponentExtensionIMEManager()),
65c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      weak_ptr_factory_(this) {
665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)InputMethodManagerImpl::~InputMethodManagerImpl() {
69a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  if (candidate_window_controller_.get())
705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    candidate_window_controller_->RemoveObserver(this);
715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void InputMethodManagerImpl::AddObserver(
745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    InputMethodManager::Observer* observer) {
755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  observers_.AddObserver(observer);
765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void InputMethodManagerImpl::AddCandidateWindowObserver(
795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    InputMethodManager::CandidateWindowObserver* observer) {
805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  candidate_window_observers_.AddObserver(observer);
815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void InputMethodManagerImpl::RemoveObserver(
845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    InputMethodManager::Observer* observer) {
855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  observers_.RemoveObserver(observer);
865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void InputMethodManagerImpl::RemoveCandidateWindowObserver(
895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    InputMethodManager::CandidateWindowObserver* observer) {
905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  candidate_window_observers_.RemoveObserver(observer);
915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void InputMethodManagerImpl::SetState(State new_state) {
945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  const State old_state = state_;
955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  state_ = new_state;
965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  switch (state_) {
975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    case STATE_LOGIN_SCREEN:
985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      break;
995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    case STATE_BROWSER_SCREEN:
1005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      if (old_state == STATE_LOCK_SCREEN)
1015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        OnScreenUnlocked();
1025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      break;
1035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    case STATE_LOCK_SCREEN:
1045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      OnScreenLocked();
1055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      break;
1062a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    case STATE_TERMINATING: {
107a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)      if (candidate_window_controller_.get())
1082a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        candidate_window_controller_.reset();
1095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      break;
1102a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    }
1115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1142a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)scoped_ptr<InputMethodDescriptors>
1155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)InputMethodManagerImpl::GetSupportedInputMethods() const {
116a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  scoped_ptr<InputMethodDescriptors> whitelist_imes =
117a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)      whitelist_.GetSupportedInputMethods();
118a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  if (!extension_ime_util::UseWrappedExtensionKeyboardLayouts())
119a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    return whitelist_imes.Pass();
120a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  return scoped_ptr<InputMethodDescriptors>(new InputMethodDescriptors).Pass();
1215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1232a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)scoped_ptr<InputMethodDescriptors>
1242a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)InputMethodManagerImpl::GetActiveInputMethods() const {
1252a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  scoped_ptr<InputMethodDescriptors> result(new InputMethodDescriptors);
1265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Build the active input method descriptors from the active input
1275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // methods cache |active_input_method_ids_|.
1285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  for (size_t i = 0; i < active_input_method_ids_.size(); ++i) {
1295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const std::string& input_method_id = active_input_method_ids_[i];
1305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const InputMethodDescriptor* descriptor =
1315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        util_.GetInputMethodDescriptorFromId(input_method_id);
1325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (descriptor) {
1335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      result->push_back(*descriptor);
1345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    } else {
1355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      std::map<std::string, InputMethodDescriptor>::const_iterator ix =
1365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          extra_input_methods_.find(input_method_id);
1375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      if (ix != extra_input_methods_.end())
1385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        result->push_back(ix->second);
1395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      else
1405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        DVLOG(1) << "Descriptor is not found for: " << input_method_id;
1415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
1425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (result->empty()) {
1445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // Initially |active_input_method_ids_| is empty. browser_tests might take
1455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // this path.
1465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    result->push_back(
147c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)        InputMethodUtil::GetFallbackInputMethodDescriptor());
1485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1492a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  return result.Pass();
1505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
152a3f7b4e666c476898878fa745f637129375cd889Ben Murdochconst std::vector<std::string>&
153a3f7b4e666c476898878fa745f637129375cd889Ben MurdochInputMethodManagerImpl::GetActiveInputMethodIds() const {
154a3f7b4e666c476898878fa745f637129375cd889Ben Murdoch  return active_input_method_ids_;
155a3f7b4e666c476898878fa745f637129375cd889Ben Murdoch}
156a3f7b4e666c476898878fa745f637129375cd889Ben Murdoch
1575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)size_t InputMethodManagerImpl::GetNumActiveInputMethods() const {
1585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return active_input_method_ids_.size();
1595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1615d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)const InputMethodDescriptor* InputMethodManagerImpl::GetInputMethodFromId(
1625d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    const std::string& input_method_id) const {
1635d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  const InputMethodDescriptor* ime = util_.GetInputMethodDescriptorFromId(
1645d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      input_method_id);
1655d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  if (!ime) {
1665d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    std::map<std::string, InputMethodDescriptor>::const_iterator ix =
1675d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        extra_input_methods_.find(input_method_id);
1685d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    if (ix != extra_input_methods_.end())
1695d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      ime = &ix->second;
1705d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  }
1715d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  return ime;
1725d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}
1735d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
1745d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)void InputMethodManagerImpl::EnableLoginLayouts(
1755d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    const std::string& language_code,
1765d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    const std::vector<std::string>& initial_layouts) {
1775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (state_ == STATE_TERMINATING)
1785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
1795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1805d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  // First, hardware keyboard layout should be shown.
1815d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  std::vector<std::string> candidates =
1825d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      util_.GetHardwareLoginInputMethodIds();
1835d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
1845d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  // Seocnd, locale based input method should be shown.
1855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Add input methods associated with the language.
1865d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  std::vector<std::string> layouts_from_locale;
1875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  util_.GetInputMethodIdsFromLanguageCode(language_code,
1885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                          kKeyboardLayoutsOnly,
1895d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                                          &layouts_from_locale);
1905d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  candidates.insert(candidates.end(), layouts_from_locale.begin(),
1915d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                    layouts_from_locale.end());
1925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  std::vector<std::string> layouts;
1945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // First, add the initial input method ID, if it's requested, to
1955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // layouts, so it appears first on the list of active input
1965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // methods at the input language status menu.
1975d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  for (size_t i = 0; i < initial_layouts.size(); ++i) {
1985d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    if (util_.IsValidInputMethodId(initial_layouts[i])) {
1995d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      if (IsLoginKeyboard(initial_layouts[i])) {
2005d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        layouts.push_back(initial_layouts[i]);
2015d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      } else {
2025d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        DVLOG(1)
2035d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)            << "EnableLoginLayouts: ignoring non-login initial keyboard layout:"
2045d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)            << initial_layouts[i];
2055d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      }
2065d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    } else if (!initial_layouts[i].empty()) {
2075d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      DVLOG(1) << "EnableLoginLayouts: ignoring non-keyboard or invalid ID: "
2085d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)               << initial_layouts[i];
2095d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    }
2105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
2115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Add candidates to layouts, while skipping duplicates.
2135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  for (size_t i = 0; i < candidates.size(); ++i) {
2145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const std::string& candidate = candidates[i];
2155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // Not efficient, but should be fine, as the two vectors are very
2165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // short (2-5 items).
217424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)    if (!Contains(layouts, candidate) && IsLoginKeyboard(candidate))
2185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      layouts.push_back(candidate);
2195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
2205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
221a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  MigrateXkbInputMethods(&layouts);
2225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  active_input_method_ids_.swap(layouts);
223a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)
224a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  // Initialize candidate window controller and widgets such as
225a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  // candidate window, infolist and mode indicator.  Note, mode
226a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  // indicator is used by only keyboard layout input methods.
227a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  if (active_input_method_ids_.size() > 1)
228a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)    MaybeInitializeCandidateWindowController();
229a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)
2305d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  // you can pass empty |initial_layout|.
231a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  ChangeInputMethod(initial_layouts.empty() ? "" :
232a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)      extension_ime_util::GetInputMethodIDByKeyboardLayout(
233a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)          initial_layouts[0]));
2345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
236a3f7b4e666c476898878fa745f637129375cd889Ben Murdoch// Adds new input method to given list.
237a3f7b4e666c476898878fa745f637129375cd889Ben Murdochbool InputMethodManagerImpl::EnableInputMethodImpl(
238a3f7b4e666c476898878fa745f637129375cd889Ben Murdoch    const std::string& input_method_id,
239f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    std::vector<std::string>* new_active_input_method_ids) const {
240f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  DCHECK(new_active_input_method_ids);
241a3f7b4e666c476898878fa745f637129375cd889Ben Murdoch  if (!util_.IsValidInputMethodId(input_method_id)) {
242a3f7b4e666c476898878fa745f637129375cd889Ben Murdoch    DVLOG(1) << "EnableInputMethod: Invalid ID: " << input_method_id;
243a3f7b4e666c476898878fa745f637129375cd889Ben Murdoch    return false;
244a3f7b4e666c476898878fa745f637129375cd889Ben Murdoch  }
245a3f7b4e666c476898878fa745f637129375cd889Ben Murdoch
246f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  if (!Contains(*new_active_input_method_ids, input_method_id))
247f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    new_active_input_method_ids->push_back(input_method_id);
248a3f7b4e666c476898878fa745f637129375cd889Ben Murdoch
249a3f7b4e666c476898878fa745f637129375cd889Ben Murdoch  return true;
250a3f7b4e666c476898878fa745f637129375cd889Ben Murdoch}
251a3f7b4e666c476898878fa745f637129375cd889Ben Murdoch
252a3f7b4e666c476898878fa745f637129375cd889Ben Murdoch// Starts or stops the system input method framework as needed.
253a3f7b4e666c476898878fa745f637129375cd889Ben Murdochvoid InputMethodManagerImpl::ReconfigureIMFramework() {
254a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  LoadNecessaryComponentExtensions();
255f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)
256f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  // Initialize candidate window controller and widgets such as
257f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  // candidate window, infolist and mode indicator.  Note, mode
258f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  // indicator is used by only keyboard layout input methods.
259a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  MaybeInitializeCandidateWindowController();
260a3f7b4e666c476898878fa745f637129375cd889Ben Murdoch}
261a3f7b4e666c476898878fa745f637129375cd889Ben Murdoch
262a3f7b4e666c476898878fa745f637129375cd889Ben Murdochbool InputMethodManagerImpl::EnableInputMethod(
263a3f7b4e666c476898878fa745f637129375cd889Ben Murdoch    const std::string& input_method_id) {
264f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  if (!EnableInputMethodImpl(input_method_id, &active_input_method_ids_))
265a3f7b4e666c476898878fa745f637129375cd889Ben Murdoch    return false;
266a3f7b4e666c476898878fa745f637129375cd889Ben Murdoch
267a3f7b4e666c476898878fa745f637129375cd889Ben Murdoch  ReconfigureIMFramework();
268a3f7b4e666c476898878fa745f637129375cd889Ben Murdoch  return true;
269a3f7b4e666c476898878fa745f637129375cd889Ben Murdoch}
270a3f7b4e666c476898878fa745f637129375cd889Ben Murdoch
2715d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)bool InputMethodManagerImpl::ReplaceEnabledInputMethods(
2725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const std::vector<std::string>& new_active_input_method_ids) {
2735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (state_ == STATE_TERMINATING)
2745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;
2755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Filter unknown or obsolete IDs.
2775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  std::vector<std::string> new_active_input_method_ids_filtered;
2785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
279a3f7b4e666c476898878fa745f637129375cd889Ben Murdoch  for (size_t i = 0; i < new_active_input_method_ids.size(); ++i)
280a3f7b4e666c476898878fa745f637129375cd889Ben Murdoch    EnableInputMethodImpl(new_active_input_method_ids[i],
281f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)                          &new_active_input_method_ids_filtered);
2825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (new_active_input_method_ids_filtered.empty()) {
2845d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    DVLOG(1) << "ReplaceEnabledInputMethods: No valid input method ID";
2855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;
2865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
2875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Copy extension IDs to |new_active_input_method_ids_filtered|. We have to
2895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // keep relative order of the extension input method IDs.
2905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  for (size_t i = 0; i < active_input_method_ids_.size(); ++i) {
2915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const std::string& input_method_id = active_input_method_ids_[i];
292c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    if (extension_ime_util::IsExtensionIME(input_method_id))
2935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      new_active_input_method_ids_filtered.push_back(input_method_id);
2945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
2955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  active_input_method_ids_.swap(new_active_input_method_ids_filtered);
296a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  MigrateXkbInputMethods(&active_input_method_ids_);
2975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
298a3f7b4e666c476898878fa745f637129375cd889Ben Murdoch  ReconfigureIMFramework();
2995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // If |current_input_method| is no longer in |active_input_method_ids_|,
3015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // ChangeInputMethod() picks the first one in |active_input_method_ids_|.
3025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ChangeInputMethod(current_input_method_.id());
3035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return true;
3045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
3055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void InputMethodManagerImpl::ChangeInputMethod(
3075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const std::string& input_method_id) {
3085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ChangeInputMethodInternal(input_method_id, false);
3095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
3105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
311a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)bool InputMethodManagerImpl::ChangeInputMethodInternal(
3125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const std::string& input_method_id,
3135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    bool show_message) {
3145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (state_ == STATE_TERMINATING)
315a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)    return false;
3165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  std::string input_method_id_to_switch = input_method_id;
3185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Sanity check.
3205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!InputMethodIsActivated(input_method_id)) {
3215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    scoped_ptr<InputMethodDescriptors> input_methods(GetActiveInputMethods());
3225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    DCHECK(!input_methods->empty());
3235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    input_method_id_to_switch = input_methods->at(0).id();
3245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (!input_method_id.empty()) {
3255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      DVLOG(1) << "Can't change the current input method to "
3265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)               << input_method_id << " since the engine is not enabled. "
3275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)               << "Switch to " << input_method_id_to_switch << " instead.";
3285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
3295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
3305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3315d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  if (!component_extension_ime_manager_->IsInitialized() &&
332a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)      (!InputMethodUtil::IsKeyboardLayout(input_method_id_to_switch) ||
333a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)       extension_ime_util::IsKeyboardLayoutExtension(
334a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)           input_method_id_to_switch))) {
335f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    // We can't change input method before the initialization of
336f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    // component extension ime manager.  ChangeInputMethod will be
337f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    // called with |pending_input_method_| when the initialization is
338f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    // done.
33990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    pending_input_method_ = input_method_id_to_switch;
34090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    return false;
34190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  }
34290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  pending_input_method_.clear();
343f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)
344f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  // Hide candidate window and info list.
345f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  if (candidate_window_controller_.get())
346f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    candidate_window_controller_->Hide();
347f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)
3485d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  // Disable the current engine handler.
3495d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  IMEEngineHandlerInterface* engine =
3505d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      IMEBridge::Get()->GetCurrentEngineHandler();
3515d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  if (engine)
3525d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    engine->Disable();
3535d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
3545d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  // Configure the next engine handler.
355a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  if (InputMethodUtil::IsKeyboardLayout(input_method_id_to_switch) &&
356a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)      !extension_ime_util::IsKeyboardLayoutExtension(
357a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)          input_method_id_to_switch)) {
3585d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    IMEBridge::Get()->SetCurrentEngineHandler(NULL);
3595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  } else {
3605d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    IMEEngineHandlerInterface* next_engine =
361a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch        profile_engine_map_[GetProfile()][input_method_id_to_switch];
362a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch    if (next_engine) {
363a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch      IMEBridge::Get()->SetCurrentEngineHandler(next_engine);
364f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)      next_engine->Enable();
365a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch    }
3665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
3675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3685d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  // TODO(komatsu): Check if it is necessary to perform the above routine
3695d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  // when the current input method is equal to |input_method_id_to_swich|.
3705d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  if (current_input_method_.id() != input_method_id_to_switch) {
371f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    // Clear property list.  Property list would be updated by
3725d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    // extension IMEs via InputMethodEngine::(Set|Update)MenuItems.
373f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    // If the current input method is a keyboard layout, empty
374f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    // properties are sufficient.
375a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    const ash::ime::InputMethodMenuItemList empty_menu_item_list;
376a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    ash::ime::InputMethodMenuManager* input_method_menu_manager =
377a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)        ash::ime::InputMethodMenuManager::GetInstance();
378a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    input_method_menu_manager->SetCurrentInputMethodMenuItemList(
379a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)            empty_menu_item_list);
380a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)
3815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const InputMethodDescriptor* descriptor = NULL;
3825d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    if (extension_ime_util::IsExtensionIME(input_method_id_to_switch)) {
3835d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      DCHECK(extra_input_methods_.find(input_method_id_to_switch) !=
3845d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)             extra_input_methods_.end());
3855d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      descriptor = &(extra_input_methods_[input_method_id_to_switch]);
3865d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    } else {
3875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      descriptor =
3885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          util_.GetInputMethodDescriptorFromId(input_method_id_to_switch);
3895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
3905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    DCHECK(descriptor);
3915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    previous_input_method_ = current_input_method_;
3935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    current_input_method_ = *descriptor;
3945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
3955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Change the keyboard layout to a preferred layout for the input method.
397a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch  if (!keyboard_->SetCurrentKeyboardLayoutByName(
398c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)          current_input_method_.GetPreferredKeyboardLayout())) {
3995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    LOG(ERROR) << "Failed to change keyboard layout to "
400c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)               << current_input_method_.GetPreferredKeyboardLayout();
4015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
4025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Update input method indicators (e.g. "US", "DV") in Chrome windows.
4045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  FOR_EACH_OBSERVER(InputMethodManager::Observer,
4055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                    observers_,
4065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                    InputMethodChanged(this, show_message));
407a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)  return true;
4085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
4095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
410c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)void InputMethodManagerImpl::OnComponentExtensionInitialized(
411c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    scoped_ptr<ComponentExtensionIMEManagerDelegate> delegate) {
412c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  DCHECK(thread_checker_.CalledOnValidThread());
413c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  component_extension_ime_manager_->Initialize(delegate.Pass());
414c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  util_.SetComponentExtensions(
415c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      component_extension_ime_manager_->GetAllIMEAsInputMethodDescriptor());
416c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
417c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  LoadNecessaryComponentExtensions();
418c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
41990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  if (!pending_input_method_.empty())
42090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    ChangeInputMethodInternal(pending_input_method_, false);
421c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)}
422c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
423c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)void InputMethodManagerImpl::LoadNecessaryComponentExtensions() {
424c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  if (!component_extension_ime_manager_->IsInitialized())
425c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    return;
426c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  // Load component extensions but also update |active_input_method_ids_| as
427c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  // some component extension IMEs may have been removed from the Chrome OS
428c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  // image. If specified component extension IME no longer exists, falling back
429c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  // to an existing IME.
430a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  std::vector<std::string> unfiltered_input_method_ids;
431a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  unfiltered_input_method_ids.swap(active_input_method_ids_);
432c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  for (size_t i = 0; i < unfiltered_input_method_ids.size(); ++i) {
433f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    if (!extension_ime_util::IsComponentExtensionIME(
434c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)        unfiltered_input_method_ids[i])) {
435c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      // Legacy IMEs or xkb layouts are alwayes active.
436c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      active_input_method_ids_.push_back(unfiltered_input_method_ids[i]);
437c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    } else if (component_extension_ime_manager_->IsWhitelisted(
438c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)        unfiltered_input_method_ids[i])) {
439c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      component_extension_ime_manager_->LoadComponentExtensionIME(
440c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)          unfiltered_input_method_ids[i]);
441c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      active_input_method_ids_.push_back(unfiltered_input_method_ids[i]);
442c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    }
443c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  }
444a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  // TODO(shuchen): move this call in ComponentExtensionIMEManager.
445a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  component_extension_ime_manager_->NotifyInitialized();
446c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)}
447c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
448a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)void InputMethodManagerImpl::ActivateInputMethodMenuItem(
4495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const std::string& key) {
4505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(!key.empty());
451f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)
452a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  if (ash::ime::InputMethodMenuManager::GetInstance()->
453a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)      HasInputMethodMenuItemForKey(key)) {
454a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    IMEEngineHandlerInterface* engine =
455a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)        IMEBridge::Get()->GetCurrentEngineHandler();
456a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    if (engine)
457a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)      engine->PropertyActivate(key);
458a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    return;
459f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  }
460f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)
461a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  DVLOG(1) << "ActivateInputMethodMenuItem: unknown key: " << key;
4625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
4635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void InputMethodManagerImpl::AddInputMethodExtension(
4655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const std::string& id,
466a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)    InputMethodEngineInterface* engine) {
4675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (state_ == STATE_TERMINATING)
4685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
4695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
470c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  if (!extension_ime_util::IsExtensionIME(id) &&
471f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)      !extension_ime_util::IsComponentExtensionIME(id)) {
4725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    DVLOG(1) << id << " is not a valid extension input method ID.";
4735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
4745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
4755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4765d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  DCHECK(engine);
4775d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
4785d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  const InputMethodDescriptor& descriptor = engine->GetDescriptor();
4795d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  extra_input_methods_[id] = descriptor;
480b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  if (Contains(enabled_extension_imes_, id) &&
481f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)      !extension_ime_util::IsComponentExtensionIME(id)) {
4825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (!Contains(active_input_method_ids_, id)) {
4835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      active_input_method_ids_.push_back(id);
4845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    } else {
4855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      DVLOG(1) << "AddInputMethodExtension: alread added: "
4865d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)               << id << ", " << descriptor.name();
4875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // Call Start() anyway, just in case.
4885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
4895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // Ensure that the input method daemon is running.
4915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    MaybeInitializeCandidateWindowController();
4925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
4935d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
494a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch  profile_engine_map_[GetProfile()][id] = engine;
4955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
4965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void InputMethodManagerImpl::RemoveInputMethodExtension(const std::string& id) {
498c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  if (!extension_ime_util::IsExtensionIME(id))
4995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    DVLOG(1) << id << " is not a valid extension input method ID.";
5005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  std::vector<std::string>::iterator i = std::find(
5025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      active_input_method_ids_.begin(), active_input_method_ids_.end(), id);
5035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (i != active_input_method_ids_.end())
5045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    active_input_method_ids_.erase(i);
5055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  extra_input_methods_.erase(id);
5065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // If |current_input_method| is no longer in |active_input_method_ids_|,
5085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // switch to the first one in |active_input_method_ids_|.
5095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ChangeInputMethod(current_input_method_.id());
5105d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
5115d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  if (IMEBridge::Get()->GetCurrentEngineHandler() ==
512a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch      profile_engine_map_[GetProfile()][id])
5135d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    IMEBridge::Get()->SetCurrentEngineHandler(NULL);
5145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
5155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void InputMethodManagerImpl::GetInputMethodExtensions(
5175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    InputMethodDescriptors* result) {
5185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Build the extension input method descriptors from the extra input
5195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // methods cache |extra_input_methods_|.
5205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  std::map<std::string, InputMethodDescriptor>::iterator iter;
5215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  for (iter = extra_input_methods_.begin(); iter != extra_input_methods_.end();
5225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)       ++iter) {
523c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    if (extension_ime_util::IsExtensionIME(iter->first))
524c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      result->push_back(iter->second);
5255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
5265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
5275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
528b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)void InputMethodManagerImpl::SetEnabledExtensionImes(
5295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    std::vector<std::string>* ids) {
530b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  enabled_extension_imes_.clear();
531b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  enabled_extension_imes_.insert(enabled_extension_imes_.end(),
532b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)                                 ids->begin(),
533b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)                                 ids->end());
5345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  bool active_imes_changed = false;
5365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  for (std::map<std::string, InputMethodDescriptor>::iterator extra_iter =
5385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)       extra_input_methods_.begin(); extra_iter != extra_input_methods_.end();
5395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)       ++extra_iter) {
540f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    if (extension_ime_util::IsComponentExtensionIME(
541c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)        extra_iter->first))
542c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      continue;  // Do not filter component extension.
5435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    std::vector<std::string>::iterator active_iter = std::find(
5445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        active_input_method_ids_.begin(), active_input_method_ids_.end(),
5455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        extra_iter->first);
5465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    bool active = active_iter != active_input_method_ids_.end();
548b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)    bool enabled = Contains(enabled_extension_imes_, extra_iter->first);
5495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
550b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)    if (active && !enabled)
5515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      active_input_method_ids_.erase(active_iter);
5525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
553b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)    if (!active && enabled)
5545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      active_input_method_ids_.push_back(extra_iter->first);
5555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
556b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)    if (active == !enabled)
5575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      active_imes_changed = true;
5585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
5595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (active_imes_changed) {
5615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    MaybeInitializeCandidateWindowController();
5625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // If |current_input_method| is no longer in |active_input_method_ids_|,
5645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // switch to the first one in |active_input_method_ids_|.
5655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    ChangeInputMethod(current_input_method_.id());
5665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
5675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
5685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5695d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)void InputMethodManagerImpl::SetInputMethodLoginDefault() {
570424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)  // Set up keyboards. For example, when |locale| is "en-US", enable US qwerty
571424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)  // and US dvorak keyboard layouts.
572424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)  if (g_browser_process && g_browser_process->local_state()) {
573424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)    const std::string locale = g_browser_process->GetApplicationLocale();
574424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)    // If the preferred keyboard for the login screen has been saved, use it.
575424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)    PrefService* prefs = g_browser_process->local_state();
576424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)    std::string initial_input_method_id =
577424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)        prefs->GetString(chromeos::language_prefs::kPreferredKeyboardLayout);
5785d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    std::vector<std::string> input_methods_to_be_enabled;
579424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)    if (initial_input_method_id.empty()) {
580424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)      // If kPreferredKeyboardLayout is not specified, use the hardware layout.
5815d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      input_methods_to_be_enabled = util_.GetHardwareLoginInputMethodIds();
5825d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    } else {
5835d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      input_methods_to_be_enabled.push_back(initial_input_method_id);
584424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)    }
5855d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    EnableLoginLayouts(locale, input_methods_to_be_enabled);
586424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)  }
587424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)}
588424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)
5895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool InputMethodManagerImpl::SwitchToNextInputMethod() {
5905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Sanity checks.
5915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (active_input_method_ids_.empty()) {
5925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    DVLOG(1) << "active input method is empty";
5935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;
5945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
595a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)
5965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (current_input_method_.id().empty()) {
5975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    DVLOG(1) << "current_input_method_ is unknown";
5985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;
5995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
6005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
601a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)  // Do not consume key event if there is only one input method is enabled.
602a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)  // Ctrl+Space or Alt+Shift may be used by other application.
603a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)  if (active_input_method_ids_.size() == 1)
604a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)    return false;
605a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)
6065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Find the next input method and switch to it.
6075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  SwitchToNextInputMethodInternal(active_input_method_ids_,
6085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                  current_input_method_.id());
6095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return true;
6105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
6115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
612a3f7b4e666c476898878fa745f637129375cd889Ben Murdochbool InputMethodManagerImpl::SwitchToPreviousInputMethod(
613a3f7b4e666c476898878fa745f637129375cd889Ben Murdoch    const ui::Accelerator& accelerator) {
6145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Sanity check.
6155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (active_input_method_ids_.empty()) {
6165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    DVLOG(1) << "active input method is empty";
6175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;
6185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
6195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
620a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)  // Do not consume key event if there is only one input method is enabled.
621a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)  // Ctrl+Space or Alt+Shift may be used by other application.
622a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)  if (active_input_method_ids_.size() == 1)
623a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)    return false;
624a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)
625a3f7b4e666c476898878fa745f637129375cd889Ben Murdoch  if (accelerator.type() == ui::ET_KEY_RELEASED)
626a3f7b4e666c476898878fa745f637129375cd889Ben Murdoch    return true;
627a3f7b4e666c476898878fa745f637129375cd889Ben Murdoch
6285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (previous_input_method_.id().empty() ||
6295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      previous_input_method_.id() == current_input_method_.id()) {
6305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return SwitchToNextInputMethod();
6315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
6325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  std::vector<std::string>::const_iterator iter =
6345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      std::find(active_input_method_ids_.begin(),
6355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                active_input_method_ids_.end(),
6365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                previous_input_method_.id());
6375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (iter == active_input_method_ids_.end()) {
6385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // previous_input_method_ is not supported.
6395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return SwitchToNextInputMethod();
6405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
6415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ChangeInputMethodInternal(*iter, true);
6425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return true;
6435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
6445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool InputMethodManagerImpl::SwitchInputMethod(
6465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const ui::Accelerator& accelerator) {
6475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Sanity check.
6485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (active_input_method_ids_.empty()) {
6495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    DVLOG(1) << "active input method is empty";
6505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;
6515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
6525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Get the list of input method ids for the |accelerator|. For example, get
6545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // { "mozc-hangul", "xkb:kr:kr104:kor" } for ui::VKEY_DBE_SBCSCHAR.
6555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  std::vector<std::string> input_method_ids_to_switch;
6565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  switch (accelerator.key_code()) {
6575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    case ui::VKEY_CONVERT:  // Henkan key on JP106 keyboard
658c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      input_method_ids_to_switch.push_back(nacl_mozc_jp_id);
6595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      break;
6605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    case ui::VKEY_NONCONVERT:  // Muhenkan key on JP106 keyboard
6615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      input_method_ids_to_switch.push_back("xkb:jp::jpn");
6625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      break;
6635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    case ui::VKEY_DBE_SBCSCHAR:  // ZenkakuHankaku key on JP106 keyboard
6645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    case ui::VKEY_DBE_DBCSCHAR:
665c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      input_method_ids_to_switch.push_back(nacl_mozc_jp_id);
6665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      input_method_ids_to_switch.push_back("xkb:jp::jpn");
6675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      break;
6685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    default:
6695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      NOTREACHED();
6705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      break;
6715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
6725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (input_method_ids_to_switch.empty()) {
6735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    DVLOG(1) << "Unexpected VKEY: " << accelerator.key_code();
6745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;
6755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
6765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
677a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  MigrateXkbInputMethods(&input_method_ids_to_switch);
678a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
6795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Obtain the intersection of input_method_ids_to_switch and
6805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // active_input_method_ids_. The order of IDs in active_input_method_ids_ is
6815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // preserved.
6825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  std::vector<std::string> ids;
6835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  for (size_t i = 0; i < input_method_ids_to_switch.size(); ++i) {
6845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const std::string& id = input_method_ids_to_switch[i];
6855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (Contains(active_input_method_ids_, id))
6865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      ids.push_back(id);
6875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
6885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (ids.empty()) {
6895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // No input method for the accelerator is active. For example, we should
6905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // just ignore VKEY_HANGUL when mozc-hangul is not active.
6915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;
6925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
6935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  SwitchToNextInputMethodInternal(ids, current_input_method_.id());
6955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return true;  // consume the accelerator.
6965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
6975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void InputMethodManagerImpl::SwitchToNextInputMethodInternal(
6995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const std::vector<std::string>& input_method_ids,
7005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const std::string& current_input_method_id) {
7015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  std::vector<std::string>::const_iterator iter =
7025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      std::find(input_method_ids.begin(),
7035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                input_method_ids.end(),
7045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                current_input_method_id);
7055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (iter != input_method_ids.end())
7065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    ++iter;
7075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (iter == input_method_ids.end())
7085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    iter = input_method_ids.begin();
7095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ChangeInputMethodInternal(*iter, true);
7105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
7115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
7125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)InputMethodDescriptor InputMethodManagerImpl::GetCurrentInputMethod() const {
7135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (current_input_method_.id().empty())
714c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    return InputMethodUtil::GetFallbackInputMethodDescriptor();
7155d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
7165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return current_input_method_;
7175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
7185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
719effb81e5f8246d0db0270817048dc992db66e9fbBen Murdochbool InputMethodManagerImpl::IsISOLevel5ShiftUsedByCurrentInputMethod() const {
720a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch  return keyboard_->IsISOLevel5ShiftAvailable();
721effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch}
722effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch
723effb81e5f8246d0db0270817048dc992db66e9fbBen Murdochbool InputMethodManagerImpl::IsAltGrUsedByCurrentInputMethod() const {
724a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch  return keyboard_->IsAltGrAvailable();
725effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch}
726effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch
727a02191e04bc25c4935f804f2c080ae28663d096dBen MurdochImeKeyboard* InputMethodManagerImpl::GetImeKeyboard() {
728a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch  return keyboard_.get();
7295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
7305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
7315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)InputMethodUtil* InputMethodManagerImpl::GetInputMethodUtil() {
7325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return &util_;
7335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
7345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
735c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)ComponentExtensionIMEManager*
736c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    InputMethodManagerImpl::GetComponentExtensionIMEManager() {
737c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  DCHECK(thread_checker_.CalledOnValidThread());
738c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  return component_extension_ime_manager_.get();
739c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)}
740c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
741c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)void InputMethodManagerImpl::InitializeComponentExtension() {
742c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  ComponentExtensionIMEManagerImpl* impl =
743c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      new ComponentExtensionIMEManagerImpl();
744c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  scoped_ptr<ComponentExtensionIMEManagerDelegate> delegate(impl);
745c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  impl->InitializeAsync(base::Bind(
746c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)                       &InputMethodManagerImpl::OnComponentExtensionInitialized,
747c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)                       weak_ptr_factory_.GetWeakPtr(),
748c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)                       base::Passed(&delegate)));
749c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)}
750c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
751c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)void InputMethodManagerImpl::Init(base::SequencedTaskRunner* ui_task_runner) {
752c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  DCHECK(thread_checker_.CalledOnValidThread());
7535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
7545d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  if (base::SysInfo::IsRunningOnChromeOS())
755a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch    keyboard_.reset(ImeKeyboard::Create());
7565d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  else
757a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch    keyboard_.reset(new FakeImeKeyboard());
758c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
759c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  // We can't call impl->Initialize here, because file thread is not available
760c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  // at this moment.
761c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  ui_task_runner->PostTask(
762c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      FROM_HERE,
763c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      base::Bind(&InputMethodManagerImpl::InitializeComponentExtension,
764c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)                 weak_ptr_factory_.GetWeakPtr()));
7655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
7665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
7675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void InputMethodManagerImpl::SetCandidateWindowControllerForTesting(
7685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    CandidateWindowController* candidate_window_controller) {
7695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  candidate_window_controller_.reset(candidate_window_controller);
7705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  candidate_window_controller_->AddObserver(this);
7715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
7725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
773a02191e04bc25c4935f804f2c080ae28663d096dBen Murdochvoid InputMethodManagerImpl::SetImeKeyboardForTesting(ImeKeyboard* keyboard) {
774a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch  keyboard_.reset(keyboard);
7755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
7765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
777c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)void InputMethodManagerImpl::InitializeComponentExtensionForTesting(
778c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    scoped_ptr<ComponentExtensionIMEManagerDelegate> delegate) {
779c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  OnComponentExtensionInitialized(delegate.Pass());
780c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)}
781c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
782a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)void InputMethodManagerImpl::CandidateClicked(int index) {
7835d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  IMEEngineHandlerInterface* engine =
7845d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      IMEBridge::Get()->GetCurrentEngineHandler();
785a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  if (engine)
786a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)    engine->CandidateClicked(index);
787a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)}
788a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)
7895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void InputMethodManagerImpl::CandidateWindowOpened() {
7905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  FOR_EACH_OBSERVER(InputMethodManager::CandidateWindowObserver,
7915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                    candidate_window_observers_,
7925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                    CandidateWindowOpened(this));
7935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
7945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
7955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void InputMethodManagerImpl::CandidateWindowClosed() {
7965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  FOR_EACH_OBSERVER(InputMethodManager::CandidateWindowObserver,
7975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                    candidate_window_observers_,
7985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                    CandidateWindowClosed(this));
7995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
8005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
8015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void InputMethodManagerImpl::OnScreenLocked() {
8025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  saved_previous_input_method_ = previous_input_method_;
8035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  saved_current_input_method_ = current_input_method_;
8045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  saved_active_input_method_ids_ = active_input_method_ids_;
8055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
8065d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  std::set<std::string> added_ids_;
8075d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
8085d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  const std::vector<std::string>& hardware_keyboard_ids =
8095d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      util_.GetHardwareLoginInputMethodIds();
8105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
8115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  active_input_method_ids_.clear();
8125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  for (size_t i = 0; i < saved_active_input_method_ids_.size(); ++i) {
8135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const std::string& input_method_id = saved_active_input_method_ids_[i];
8145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // Skip if it's not a keyboard layout. Drop input methods including
8155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // extension ones.
8165d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    if (!IsLoginKeyboard(input_method_id) ||
8175d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        added_ids_.find(input_method_id) != added_ids_.end())
8185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      continue;
8195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    active_input_method_ids_.push_back(input_method_id);
8205d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    added_ids_.insert(input_method_id);
8215d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  }
8225d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
8235d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  // We'll add the hardware keyboard if it's not included in
8245d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  // |active_input_method_ids_| so that the user can always use the hardware
8255d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  // keyboard on the screen locker.
8265d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  for (size_t i = 0; i < hardware_keyboard_ids.size(); ++i) {
8275d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    if (added_ids_.find(hardware_keyboard_ids[i]) == added_ids_.end()) {
8285d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      active_input_method_ids_.push_back(hardware_keyboard_ids[i]);
8295d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      added_ids_.insert(hardware_keyboard_ids[i]);
8305d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    }
8315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
8325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
8335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ChangeInputMethod(current_input_method_.id());
8345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
8355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
8365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void InputMethodManagerImpl::OnScreenUnlocked() {
8375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  previous_input_method_ = saved_previous_input_method_;
8385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  current_input_method_ = saved_current_input_method_;
8395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  active_input_method_ids_ = saved_active_input_method_ids_;
8405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
8415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ChangeInputMethod(current_input_method_.id());
8425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
8435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
8445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool InputMethodManagerImpl::InputMethodIsActivated(
8455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const std::string& input_method_id) {
8465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return Contains(active_input_method_ids_, input_method_id);
8475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
8485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
8495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void InputMethodManagerImpl::MaybeInitializeCandidateWindowController() {
8505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (candidate_window_controller_.get())
8515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
8525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
8535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  candidate_window_controller_.reset(
8545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      CandidateWindowController::CreateCandidateWindowController());
855a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  candidate_window_controller_->AddObserver(this);
8565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
8575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
858a02191e04bc25c4935f804f2c080ae28663d096dBen MurdochProfile* InputMethodManagerImpl::GetProfile() const {
859a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch  return ProfileManager::GetActiveUserProfile();
860a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch}
861a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch
8625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}  // namespace input_method
8635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}  // namespace chromeos
864