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)
903b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)#include <sstream>
1003b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)
11a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)#include "ash/ime/input_method_menu_item.h"
12a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)#include "ash/ime/input_method_menu_manager.h"
135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/basictypes.h"
14c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)#include "base/bind.h"
15c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)#include "base/location.h"
165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/memory/scoped_ptr.h"
171320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci#include "base/metrics/histogram.h"
181320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci#include "base/metrics/sparse_histogram.h"
19424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)#include "base/prefs/pref_service.h"
20f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)#include "base/strings/string_split.h"
215e3f23d412006dc4db4e659864679f29341e113fTorne (Richard Coles)#include "base/strings/string_util.h"
225e3f23d412006dc4db4e659864679f29341e113fTorne (Richard Coles)#include "base/strings/stringprintf.h"
235d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#include "base/sys_info.h"
24424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)#include "chrome/browser/browser_process.h"
255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/browser/chromeos/input_method/candidate_window_controller.h"
26c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)#include "chrome/browser/chromeos/input_method/component_extension_ime_manager_impl.h"
27a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)#include "chrome/browser/chromeos/input_method/input_method_engine.h"
285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/browser/chromeos/language_preferences.h"
2903b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)#include "chrome/browser/chromeos/login/session/user_session_manager.h"
3003b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)#include "chrome/browser/chromeos/profiles/profile_helper.h"
31a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch#include "chrome/browser/profiles/profile_manager.h"
32f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)#include "chrome/common/pref_names.h"
33c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)#include "chromeos/ime/component_extension_ime_manager.h"
34c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)#include "chromeos/ime/extension_ime_util.h"
35a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch#include "chromeos/ime/fake_ime_keyboard.h"
36a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch#include "chromeos/ime/ime_keyboard.h"
372a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "chromeos/ime/input_method_delegate.h"
3803b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)#include "components/user_manager/user_manager.h"
39ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch#include "third_party/icu/source/common/unicode/uloc.h"
405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "ui/base/accelerators/accelerator.h"
411320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci#include "ui/keyboard/keyboard_controller.h"
421320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci#include "ui/keyboard/keyboard_util.h"
435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)namespace chromeos {
455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)namespace input_method {
465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)namespace {
485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool Contains(const std::vector<std::string>& container,
505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)              const std::string& value) {
515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return std::find(container.begin(), container.end(), value) !=
525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      container.end();
535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
551320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tuccienum InputMethodCategory {
561320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  INPUT_METHOD_CATEGORY_UNKNOWN = 0,
571320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  INPUT_METHOD_CATEGORY_XKB,  // XKB input methods
581320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  INPUT_METHOD_CATEGORY_ZH,   // Chinese input methods
591320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  INPUT_METHOD_CATEGORY_JA,   // Japanese input methods
601320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  INPUT_METHOD_CATEGORY_KO,   // Korean input methods
611320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  INPUT_METHOD_CATEGORY_M17N, // Multilingualization input methods
621320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  INPUT_METHOD_CATEGORY_T13N, // Transliteration input methods
631320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  INPUT_METHOD_CATEGORY_MAX
641320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci};
651320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
661320f92c476a1ad9d19dba2a48c72b75566198e9Primiano TucciInputMethodCategory GetInputMethodCategory(const std::string& input_method_id,
671320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci                                           char* first_char = NULL) {
681320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  const std::string component_id =
691320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci      extension_ime_util::GetComponentIDByInputMethodID(input_method_id);
701320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  InputMethodCategory category = INPUT_METHOD_CATEGORY_UNKNOWN;
711320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  char ch = 0;
721320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  if (StartsWithASCII(component_id, "xkb:", true)) {
731320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    ch = component_id[4];
741320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    category = INPUT_METHOD_CATEGORY_XKB;
751320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  } else if (StartsWithASCII(component_id, "zh-", true)) {
761320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    size_t pos = component_id.find("-t-i0-");
771320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    if (pos > 0)
781320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci      pos += 6;
791320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    ch = component_id[pos];
801320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    category = INPUT_METHOD_CATEGORY_ZH;
811320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  } else if (StartsWithASCII(component_id, "nacl_mozc_", true)) {
821320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    ch = component_id[10];
831320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    category = INPUT_METHOD_CATEGORY_JA;
841320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  } else if (StartsWithASCII(component_id, "hangul_", true)) {
851320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    ch = component_id[7];
861320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    category = INPUT_METHOD_CATEGORY_KO;
871320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  } else if (StartsWithASCII(component_id, "vkd_", true)) {
881320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    ch = component_id[4];
891320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    category = INPUT_METHOD_CATEGORY_M17N;
901320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  } else if (component_id.find("-t-i0-") > 0) {
911320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    ch = component_id[0];
921320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    category = INPUT_METHOD_CATEGORY_T13N;
931320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  }
941320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
951320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  if (first_char)
961320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    *first_char = ch;
971320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  return category;
981320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci}
991320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
1005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}  // namespace
1015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
10203b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)// ------------------------ InputMethodManagerImpl::StateImpl
103a3f7b4e666c476898878fa745f637129375cd889Ben Murdoch
10403b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)InputMethodManagerImpl::StateImpl::StateImpl(InputMethodManagerImpl* manager,
10503b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)                                             Profile* profile)
10603b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)    : profile(profile), manager_(manager) {
107a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)}
108a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
10903b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)InputMethodManagerImpl::StateImpl::~StateImpl() {
1105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
11203b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)void InputMethodManagerImpl::StateImpl::InitFrom(const StateImpl& other) {
11303b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  previous_input_method = other.previous_input_method;
11403b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  current_input_method = other.current_input_method;
1155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
11603b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  active_input_method_ids = other.active_input_method_ids;
1175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
11803b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  pending_input_method_id = other.pending_input_method_id;
1195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
12003b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  enabled_extension_imes = other.enabled_extension_imes;
12103b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  extra_input_methods = other.extra_input_methods;
1225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
12403b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)bool InputMethodManagerImpl::StateImpl::IsActive() const {
12503b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  return manager_->state_.get() == this;
1265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
12803b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)std::string InputMethodManagerImpl::StateImpl::Dump() const {
12903b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  std::ostringstream os;
13003b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)
13103b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  os << "################# "
13203b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)     << (profile ? profile->GetProfileName() : std::string("NULL"))
13303b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)     << " #################\n";
13403b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)
13503b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  os << "previous_input_method: '"
13603b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)     << previous_input_method.GetPreferredKeyboardLayout() << "'\n";
13703b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  os << "current_input_method: '"
13803b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)     << current_input_method.GetPreferredKeyboardLayout() << "'\n";
13903b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  os << "active_input_method_ids (size=" << active_input_method_ids.size()
14003b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)     << "):";
14103b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  for (size_t i = 0; i < active_input_method_ids.size(); ++i) {
14203b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)    os << " '" << active_input_method_ids[i] << "',";
1435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
14403b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  os << "\n";
14503b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  os << "enabled_extension_imes (size=" << enabled_extension_imes.size()
14603b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)     << "):";
14703b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  for (size_t i = 0; i < enabled_extension_imes.size(); ++i) {
14803b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)    os << " '" << enabled_extension_imes[i] << "'\n";
14903b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  }
15003b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  os << "\n";
15103b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  os << "extra_input_methods (size=" << extra_input_methods.size() << "):";
15203b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  for (std::map<std::string, InputMethodDescriptor>::const_iterator it =
15303b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)           extra_input_methods.begin();
15403b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)       it != extra_input_methods.end();
15503b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)       ++it) {
15603b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)    os << " '" << it->first << "' => '" << it->second.id() << "',\n";
15703b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  }
15803b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  os << "pending_input_method_id: '" << pending_input_method_id << "'\n";
15903b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)
16003b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  return os.str();
1615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
16303b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)scoped_refptr<InputMethodManager::State>
16403b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)InputMethodManagerImpl::StateImpl::Clone() const {
16503b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  scoped_refptr<StateImpl> new_state(new StateImpl(this->manager_, profile));
16603b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  new_state->InitFrom(*this);
16703b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  return scoped_refptr<InputMethodManager::State>(new_state.get());
1685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1702a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)scoped_ptr<InputMethodDescriptors>
17103b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)InputMethodManagerImpl::StateImpl::GetActiveInputMethods() const {
1722a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  scoped_ptr<InputMethodDescriptors> result(new InputMethodDescriptors);
1735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Build the active input method descriptors from the active input
17403b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  // methods cache |active_input_method_ids|.
17503b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  for (size_t i = 0; i < active_input_method_ids.size(); ++i) {
17603b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)    const std::string& input_method_id = active_input_method_ids[i];
1775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const InputMethodDescriptor* descriptor =
17803b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)        manager_->util_.GetInputMethodDescriptorFromId(input_method_id);
1795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (descriptor) {
1805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      result->push_back(*descriptor);
1815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    } else {
1825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      std::map<std::string, InputMethodDescriptor>::const_iterator ix =
18303b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)          extra_input_methods.find(input_method_id);
18403b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)      if (ix != extra_input_methods.end())
1855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        result->push_back(ix->second);
1865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      else
1875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        DVLOG(1) << "Descriptor is not found for: " << input_method_id;
1885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
1895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (result->empty()) {
19103b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)    // Initially |active_input_method_ids| is empty. browser_tests might take
1925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // this path.
1935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    result->push_back(
194c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)        InputMethodUtil::GetFallbackInputMethodDescriptor());
1955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1962a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  return result.Pass();
1975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
199a3f7b4e666c476898878fa745f637129375cd889Ben Murdochconst std::vector<std::string>&
20003b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)InputMethodManagerImpl::StateImpl::GetActiveInputMethodIds() const {
20103b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  return active_input_method_ids;
202a3f7b4e666c476898878fa745f637129375cd889Ben Murdoch}
203a3f7b4e666c476898878fa745f637129375cd889Ben Murdoch
20403b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)size_t InputMethodManagerImpl::StateImpl::GetNumActiveInputMethods() const {
20503b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  return active_input_method_ids.size();
2065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
20803b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)const InputMethodDescriptor*
20903b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)InputMethodManagerImpl::StateImpl::GetInputMethodFromId(
2105d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    const std::string& input_method_id) const {
21103b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  const InputMethodDescriptor* ime =
21203b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)      manager_->util_.GetInputMethodDescriptorFromId(input_method_id);
2135d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  if (!ime) {
2145d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    std::map<std::string, InputMethodDescriptor>::const_iterator ix =
21503b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)        extra_input_methods.find(input_method_id);
21603b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)    if (ix != extra_input_methods.end())
2175d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      ime = &ix->second;
2185d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  }
2195d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  return ime;
2205d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}
2215d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
22203b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)void InputMethodManagerImpl::StateImpl::EnableLoginLayouts(
2235d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    const std::string& language_code,
2245d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    const std::vector<std::string>& initial_layouts) {
22503b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  if (manager_->ui_session_ == STATE_TERMINATING)
2265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
2275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2285d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  // First, hardware keyboard layout should be shown.
2295d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  std::vector<std::string> candidates =
23003b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)      manager_->util_.GetHardwareLoginInputMethodIds();
2315d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
23203b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  // Second, locale based input method should be shown.
2335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Add input methods associated with the language.
2345d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  std::vector<std::string> layouts_from_locale;
23503b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  manager_->util_.GetInputMethodIdsFromLanguageCode(
23603b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)      language_code, kKeyboardLayoutsOnly, &layouts_from_locale);
2375d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  candidates.insert(candidates.end(), layouts_from_locale.begin(),
2385d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                    layouts_from_locale.end());
2395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  std::vector<std::string> layouts;
2415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // First, add the initial input method ID, if it's requested, to
2425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // layouts, so it appears first on the list of active input
2435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // methods at the input language status menu.
2445d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  for (size_t i = 0; i < initial_layouts.size(); ++i) {
24503b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)    if (manager_->util_.IsValidInputMethodId(initial_layouts[i])) {
24603b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)      if (manager_->IsLoginKeyboard(initial_layouts[i])) {
2475d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        layouts.push_back(initial_layouts[i]);
2485d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      } else {
2495d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        DVLOG(1)
2505d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)            << "EnableLoginLayouts: ignoring non-login initial keyboard layout:"
2515d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)            << initial_layouts[i];
2525d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      }
2535d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    } else if (!initial_layouts[i].empty()) {
2545d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      DVLOG(1) << "EnableLoginLayouts: ignoring non-keyboard or invalid ID: "
2555d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)               << initial_layouts[i];
2565d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    }
2575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
2585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Add candidates to layouts, while skipping duplicates.
2605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  for (size_t i = 0; i < candidates.size(); ++i) {
2615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const std::string& candidate = candidates[i];
2625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // Not efficient, but should be fine, as the two vectors are very
2635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // short (2-5 items).
26403b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)    if (!Contains(layouts, candidate) && manager_->IsLoginKeyboard(candidate))
2655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      layouts.push_back(candidate);
2665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
2675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
26803b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  manager_->MigrateInputMethods(&layouts);
26903b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  active_input_method_ids.swap(layouts);
27003b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)
27103b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  if (IsActive()) {
27203b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)    // Initialize candidate window controller and widgets such as
27303b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)    // candidate window, infolist and mode indicator.  Note, mode
27403b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)    // indicator is used by only keyboard layout input methods.
27503b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)    if (active_input_method_ids.size() > 1)
27603b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)      manager_->MaybeInitializeCandidateWindowController();
27703b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)
27803b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)    // you can pass empty |initial_layout|.
27903b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)    ChangeInputMethod(initial_layouts.empty()
28003b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)                          ? std::string()
28103b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)                          : extension_ime_util::GetInputMethodIDByEngineID(
28203b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)                                initial_layouts[0]),
28303b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)                      false);
28403b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  }
28503b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)}
286a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)
28703b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)void InputMethodManagerImpl::StateImpl::EnableLockScreenLayouts() {
28803b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  std::set<std::string> added_ids;
289a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)
29003b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  const std::vector<std::string>& hardware_keyboard_ids =
29103b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)      manager_->util_.GetHardwareLoginInputMethodIds();
29203b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)
29303b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  std::vector<std::string> new_active_input_method_ids;
29403b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  for (size_t i = 0; i < active_input_method_ids.size(); ++i) {
29503b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)    const std::string& input_method_id = active_input_method_ids[i];
29603b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)    // Skip if it's not a keyboard layout. Drop input methods including
29703b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)    // extension ones.
29803b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)    if (!manager_->IsLoginKeyboard(input_method_id) ||
29903b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)        added_ids.count(input_method_id)) {
30003b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)      continue;
30103b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)    }
30203b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)    new_active_input_method_ids.push_back(input_method_id);
30303b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)    added_ids.insert(input_method_id);
30403b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  }
30503b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)
30603b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  // We'll add the hardware keyboard if it's not included in
30703b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  // |active_input_method_ids| so that the user can always use the hardware
30803b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  // keyboard on the screen locker.
30903b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  for (size_t i = 0; i < hardware_keyboard_ids.size(); ++i) {
31003b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)    if (added_ids.count(hardware_keyboard_ids[i]))
31103b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)      continue;
31203b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)    new_active_input_method_ids.push_back(hardware_keyboard_ids[i]);
31303b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)    added_ids.insert(hardware_keyboard_ids[i]);
31403b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  }
31503b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)
31603b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  active_input_method_ids.swap(new_active_input_method_ids);
31703b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)
31803b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  // Re-check current_input_method.
31903b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  ChangeInputMethod(current_input_method.id(), false);
3205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
3215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
322a3f7b4e666c476898878fa745f637129375cd889Ben Murdoch// Adds new input method to given list.
32303b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)bool InputMethodManagerImpl::StateImpl::EnableInputMethodImpl(
324a3f7b4e666c476898878fa745f637129375cd889Ben Murdoch    const std::string& input_method_id,
325f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    std::vector<std::string>* new_active_input_method_ids) const {
326f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  DCHECK(new_active_input_method_ids);
32703b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  if (!manager_->util_.IsValidInputMethodId(input_method_id)) {
328a3f7b4e666c476898878fa745f637129375cd889Ben Murdoch    DVLOG(1) << "EnableInputMethod: Invalid ID: " << input_method_id;
329a3f7b4e666c476898878fa745f637129375cd889Ben Murdoch    return false;
330a3f7b4e666c476898878fa745f637129375cd889Ben Murdoch  }
331a3f7b4e666c476898878fa745f637129375cd889Ben Murdoch
332f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  if (!Contains(*new_active_input_method_ids, input_method_id))
333f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    new_active_input_method_ids->push_back(input_method_id);
334a3f7b4e666c476898878fa745f637129375cd889Ben Murdoch
335a3f7b4e666c476898878fa745f637129375cd889Ben Murdoch  return true;
336a3f7b4e666c476898878fa745f637129375cd889Ben Murdoch}
337a3f7b4e666c476898878fa745f637129375cd889Ben Murdoch
33803b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)bool InputMethodManagerImpl::StateImpl::EnableInputMethod(
339a3f7b4e666c476898878fa745f637129375cd889Ben Murdoch    const std::string& input_method_id) {
34003b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  if (!EnableInputMethodImpl(input_method_id, &active_input_method_ids))
341a3f7b4e666c476898878fa745f637129375cd889Ben Murdoch    return false;
342a3f7b4e666c476898878fa745f637129375cd889Ben Murdoch
34303b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  manager_->ReconfigureIMFramework(this);
344a3f7b4e666c476898878fa745f637129375cd889Ben Murdoch  return true;
345a3f7b4e666c476898878fa745f637129375cd889Ben Murdoch}
346a3f7b4e666c476898878fa745f637129375cd889Ben Murdoch
34703b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)bool InputMethodManagerImpl::StateImpl::ReplaceEnabledInputMethods(
3485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const std::vector<std::string>& new_active_input_method_ids) {
34903b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  if (manager_->ui_session_ == STATE_TERMINATING)
3505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;
3515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Filter unknown or obsolete IDs.
3535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  std::vector<std::string> new_active_input_method_ids_filtered;
3545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
355a3f7b4e666c476898878fa745f637129375cd889Ben Murdoch  for (size_t i = 0; i < new_active_input_method_ids.size(); ++i)
356a3f7b4e666c476898878fa745f637129375cd889Ben Murdoch    EnableInputMethodImpl(new_active_input_method_ids[i],
357f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)                          &new_active_input_method_ids_filtered);
3585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (new_active_input_method_ids_filtered.empty()) {
3605d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    DVLOG(1) << "ReplaceEnabledInputMethods: No valid input method ID";
3615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;
3625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
3635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Copy extension IDs to |new_active_input_method_ids_filtered|. We have to
3655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // keep relative order of the extension input method IDs.
36603b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  for (size_t i = 0; i < active_input_method_ids.size(); ++i) {
36703b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)    const std::string& input_method_id = active_input_method_ids[i];
368c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    if (extension_ime_util::IsExtensionIME(input_method_id))
3695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      new_active_input_method_ids_filtered.push_back(input_method_id);
3705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
37103b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  active_input_method_ids.swap(new_active_input_method_ids_filtered);
37203b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  manager_->MigrateInputMethods(&active_input_method_ids);
3735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
37403b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  manager_->ReconfigureIMFramework(this);
3755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
37603b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  // If |current_input_method| is no longer in |active_input_method_ids|,
37703b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  // ChangeInputMethod() picks the first one in |active_input_method_ids|.
37803b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  ChangeInputMethod(current_input_method.id(), false);
3791320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
3801320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  // Record histogram for active input method count.
3811320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  UMA_HISTOGRAM_COUNTS("InputMethod.ActiveCount",
3821320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci                       active_input_method_ids.size());
3831320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
3845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return true;
3855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
3865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
38703b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)void InputMethodManagerImpl::StateImpl::ChangeInputMethod(
3885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const std::string& input_method_id,
3895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    bool show_message) {
39003b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  if (manager_->ui_session_ == STATE_TERMINATING)
39103b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)    return;
3925f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
39303b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  bool notify_menu = false;
39403b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  // For 3rd party IME, when the user just logged in, SetEnabledExtensionImes
39503b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  // happens after activating the 3rd party IME.
39603b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  // So here to record the 3rd party IME to be activated, and activate it
39703b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  // when SetEnabledExtensionImes happens later.
39803b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  if (MethodAwaitsExtensionLoad(input_method_id))
39903b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)    pending_input_method_id = input_method_id;
40003b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)
40103b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  // Always lookup input method, even if it is the same as
40203b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  // |current_input_method| because If it is no longer in
40303b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  // |active_input_method_ids|, pick the first one in
40403b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  // |active_input_method_ids|.
40503b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  const InputMethodDescriptor* descriptor =
40603b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)      manager_->LookupInputMethod(input_method_id, this);
40703b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  if (descriptor->id() != current_input_method.id()) {
40803b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)    previous_input_method = current_input_method;
40903b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)    current_input_method = *descriptor;
41003b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)    notify_menu = true;
4115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
4125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
41303b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  // Always change input method even if it is the same.
41403b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  // TODO(komatsu): Revisit if this is neccessary.
41503b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  if (IsActive())
41603b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)    manager_->ChangeInputMethodInternal(*descriptor, show_message, notify_menu);
4171320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  manager_->RecordInputMethodUsage(current_input_method.id());
418c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)}
419c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
42003b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)bool InputMethodManagerImpl::StateImpl::MethodAwaitsExtensionLoad(
42103b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)    const std::string& input_method_id) const {
42203b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  // For 3rd party IME, when the user just logged in, SetEnabledExtensionImes
42303b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  // happens after activating the 3rd party IME.
42403b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  // So here to record the 3rd party IME to be activated, and activate it
42503b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  // when SetEnabledExtensionImes happens later.
42603b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  return !InputMethodIsActivated(input_method_id) &&
42703b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)         extension_ime_util::IsExtensionIME(input_method_id);
4285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
4295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
43003b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)void InputMethodManagerImpl::StateImpl::AddInputMethodExtension(
4315f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    const std::string& extension_id,
4325f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    const InputMethodDescriptors& descriptors,
433a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)    InputMethodEngineInterface* engine) {
43403b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  if (manager_->ui_session_ == STATE_TERMINATING)
4355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
4365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
437116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  DCHECK(engine);
438116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch
43903b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  manager_->engine_map_[extension_id] = engine;
4405f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
4415f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  bool contain = false;
4425f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  for (size_t i = 0; i < descriptors.size(); i++) {
4435f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    const InputMethodDescriptor& descriptor = descriptors[i];
4445f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    const std::string& id = descriptor.id();
44503b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)    extra_input_methods[id] = descriptor;
44603b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)    if (Contains(enabled_extension_imes, id)) {
44703b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)      if (!Contains(active_input_method_ids, id)) {
44803b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)        active_input_method_ids.push_back(id);
4495f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)      } else {
4505f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)        DVLOG(1) << "AddInputMethodExtension: already added: " << id << ", "
4515f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)                 << descriptor.name();
4525f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)      }
4535f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)      contain = true;
4545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
4555f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  }
4565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
45703b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  if (IsActive()) {
45803b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)    if (extension_id == extension_ime_util::GetExtensionIDFromInputMethodID(
45903b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)                            current_input_method.id())) {
46003b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)      IMEBridge::Get()->SetCurrentEngineHandler(engine);
46103b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)      engine->Enable(extension_ime_util::GetComponentIDByInputMethodID(
46203b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)          current_input_method.id()));
46303b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)    }
46403b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)
46503b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)    // Ensure that the input method daemon is running.
46603b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)    if (contain)
46703b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)      manager_->MaybeInitializeCandidateWindowController();
46803b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  }
4695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
4705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
47103b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)void InputMethodManagerImpl::StateImpl::RemoveInputMethodExtension(
4725f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    const std::string& extension_id) {
4735f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  // Remove the active input methods with |extension_id|.
4745f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  std::vector<std::string> new_active_input_method_ids;
47503b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  for (size_t i = 0; i < active_input_method_ids.size(); ++i) {
4765f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    if (extension_id != extension_ime_util::GetExtensionIDFromInputMethodID(
47703b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)                            active_input_method_ids[i]))
47803b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)      new_active_input_method_ids.push_back(active_input_method_ids[i]);
4795f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  }
48003b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  active_input_method_ids.swap(new_active_input_method_ids);
4815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4825f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  // Remove the extra input methods with |extension_id|.
4835f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  std::map<std::string, InputMethodDescriptor> new_extra_input_methods;
4845f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  for (std::map<std::string, InputMethodDescriptor>::iterator i =
48503b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)           extra_input_methods.begin();
48603b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)       i != extra_input_methods.end();
4875f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)       ++i) {
4885f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    if (extension_id !=
4895f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)        extension_ime_util::GetExtensionIDFromInputMethodID(i->first))
4905f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)      new_extra_input_methods[i->first] = i->second;
4915f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  }
49203b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  extra_input_methods.swap(new_extra_input_methods);
4935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
49403b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  if (IsActive()) {
49503b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)    if (IMEBridge::Get()->GetCurrentEngineHandler() ==
49603b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)        manager_->engine_map_[extension_id]) {
49703b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)      IMEBridge::Get()->SetCurrentEngineHandler(NULL);
49803b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)    }
49903b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)    manager_->engine_map_.erase(extension_id);
500116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  }
50103b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)
50203b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  // If |current_input_method| is no longer in |active_input_method_ids|,
50303b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  // switch to the first one in |active_input_method_ids|.
50403b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  ChangeInputMethod(current_input_method.id(), false);
5055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
5065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
50703b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)void InputMethodManagerImpl::StateImpl::GetInputMethodExtensions(
5085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    InputMethodDescriptors* result) {
5095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Build the extension input method descriptors from the extra input
51003b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  // methods cache |extra_input_methods|.
5115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  std::map<std::string, InputMethodDescriptor>::iterator iter;
51203b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  for (iter = extra_input_methods.begin(); iter != extra_input_methods.end();
5135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)       ++iter) {
514c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    if (extension_ime_util::IsExtensionIME(iter->first))
515c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      result->push_back(iter->second);
5165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
5175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
5185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
51903b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)void InputMethodManagerImpl::StateImpl::SetEnabledExtensionImes(
5205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    std::vector<std::string>* ids) {
52103b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  enabled_extension_imes.clear();
52203b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  enabled_extension_imes.insert(
52303b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)      enabled_extension_imes.end(), ids->begin(), ids->end());
5245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  bool active_imes_changed = false;
5256e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)  bool switch_to_pending = false;
5265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  for (std::map<std::string, InputMethodDescriptor>::iterator extra_iter =
52803b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)           extra_input_methods.begin();
52903b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)       extra_iter != extra_input_methods.end();
5305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)       ++extra_iter) {
53103b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)    if (extension_ime_util::IsComponentExtensionIME(extra_iter->first))
532c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      continue;  // Do not filter component extension.
5336e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)
53403b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)    if (pending_input_method_id == extra_iter->first)
5356e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)      switch_to_pending = true;
5366e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)
53703b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)    std::vector<std::string>::iterator active_iter =
53803b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)        std::find(active_input_method_ids.begin(),
53903b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)                  active_input_method_ids.end(),
54003b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)                  extra_iter->first);
5415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
54203b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)    bool active = active_iter != active_input_method_ids.end();
54303b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)    bool enabled = Contains(enabled_extension_imes, extra_iter->first);
5445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
545b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)    if (active && !enabled)
54603b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)      active_input_method_ids.erase(active_iter);
5475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
548b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)    if (!active && enabled)
54903b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)      active_input_method_ids.push_back(extra_iter->first);
5505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
551b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)    if (active == !enabled)
5525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      active_imes_changed = true;
5535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
5545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
55503b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  if (IsActive() && active_imes_changed) {
55603b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)    manager_->MaybeInitializeCandidateWindowController();
5575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5586e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)    if (switch_to_pending) {
55903b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)      ChangeInputMethod(pending_input_method_id, false);
56003b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)      pending_input_method_id.clear();
5616e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)    } else {
5626e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)      // If |current_input_method| is no longer in |active_input_method_ids_|,
5636e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)      // switch to the first one in |active_input_method_ids_|.
56403b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)      ChangeInputMethod(current_input_method.id(), false);
5656e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)    }
5665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
5675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
5685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
56903b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)void InputMethodManagerImpl::StateImpl::SetInputMethodLoginDefaultFromVPD(
57003b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)    const std::string& locale,
57103b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)    const std::string& oem_layout) {
572f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  std::string layout;
573f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  if (!oem_layout.empty()) {
574f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)    // If the OEM layout information is provided, use it.
575f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)    layout = oem_layout;
576f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  } else {
577f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)    // Otherwise, determine the hardware keyboard from the locale.
578f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)    std::vector<std::string> input_method_ids;
57903b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)    if (manager_->util_.GetInputMethodIdsFromLanguageCode(
58003b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)            locale,
58103b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)            chromeos::input_method::kKeyboardLayoutsOnly,
58203b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)            &input_method_ids)) {
583f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)      // The output list |input_method_ids| is sorted by popularity, hence
584f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)      // input_method_ids[0] now contains the most popular keyboard layout
585f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)      // for the given locale.
586f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)      DCHECK_GE(input_method_ids.size(), 1U);
587f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)      layout = input_method_ids[0];
588f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)    }
589f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  }
590f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)
591f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  if (layout.empty())
592f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)    return;
593f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)
594f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  std::vector<std::string> layouts;
595f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  base::SplitString(layout, ',', &layouts);
59603b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  manager_->MigrateInputMethods(&layouts);
597f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)
598f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  PrefService* prefs = g_browser_process->local_state();
599f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  prefs->SetString(prefs::kHardwareKeyboardLayout, JoinString(layouts, ","));
600f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)
601f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  // This asks the file thread to save the prefs (i.e. doesn't block).
602f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  // The latest values of Local State reside in memory so we can safely
603f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  // get the value of kHardwareKeyboardLayout even if the data is not
604f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  // yet saved to disk.
605f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  prefs->CommitPendingWrite();
606f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)
60703b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  manager_->util_.UpdateHardwareLayoutCache();
608f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)
609f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  EnableLoginLayouts(locale, layouts);
61003b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  manager_->LoadNecessaryComponentExtensions(this);
611f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)}
612f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)
61303b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)void InputMethodManagerImpl::StateImpl::SetInputMethodLoginDefault() {
614424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)  // Set up keyboards. For example, when |locale| is "en-US", enable US qwerty
615424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)  // and US dvorak keyboard layouts.
616424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)  if (g_browser_process && g_browser_process->local_state()) {
617424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)    const std::string locale = g_browser_process->GetApplicationLocale();
618424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)    // If the preferred keyboard for the login screen has been saved, use it.
619424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)    PrefService* prefs = g_browser_process->local_state();
620424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)    std::string initial_input_method_id =
621424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)        prefs->GetString(chromeos::language_prefs::kPreferredKeyboardLayout);
6225d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    std::vector<std::string> input_methods_to_be_enabled;
623424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)    if (initial_input_method_id.empty()) {
624424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)      // If kPreferredKeyboardLayout is not specified, use the hardware layout.
62503b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)      input_methods_to_be_enabled =
62603b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)          manager_->util_.GetHardwareLoginInputMethodIds();
6275d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    } else {
6285d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      input_methods_to_be_enabled.push_back(initial_input_method_id);
629424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)    }
6305d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    EnableLoginLayouts(locale, input_methods_to_be_enabled);
63103b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)    manager_->LoadNecessaryComponentExtensions(this);
632424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)  }
633424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)}
634424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)
63503b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)bool InputMethodManagerImpl::StateImpl::SwitchToNextInputMethod() {
6365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Sanity checks.
63703b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  if (active_input_method_ids.empty()) {
6385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    DVLOG(1) << "active input method is empty";
6395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;
6405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
641a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)
64203b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  if (current_input_method.id().empty()) {
64303b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)    DVLOG(1) << "current_input_method is unknown";
6445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;
6455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
6465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
647a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)  // Do not consume key event if there is only one input method is enabled.
648a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)  // Ctrl+Space or Alt+Shift may be used by other application.
64903b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  if (active_input_method_ids.size() == 1)
650a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)    return false;
651a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)
6525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Find the next input method and switch to it.
65303b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  SwitchToNextInputMethodInternal(active_input_method_ids,
65403b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)                                  current_input_method.id());
6555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return true;
6565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
6575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
65803b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)bool InputMethodManagerImpl::StateImpl::SwitchToPreviousInputMethod(
659a3f7b4e666c476898878fa745f637129375cd889Ben Murdoch    const ui::Accelerator& accelerator) {
6605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Sanity check.
66103b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  if (active_input_method_ids.empty()) {
6625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    DVLOG(1) << "active input method is empty";
6635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;
6645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
6655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
666a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)  // Do not consume key event if there is only one input method is enabled.
667a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)  // Ctrl+Space or Alt+Shift may be used by other application.
66803b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  if (active_input_method_ids.size() == 1)
669a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)    return false;
670a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)
671a3f7b4e666c476898878fa745f637129375cd889Ben Murdoch  if (accelerator.type() == ui::ET_KEY_RELEASED)
672a3f7b4e666c476898878fa745f637129375cd889Ben Murdoch    return true;
673a3f7b4e666c476898878fa745f637129375cd889Ben Murdoch
67403b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  if (previous_input_method.id().empty() ||
67503b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)      previous_input_method.id() == current_input_method.id()) {
6765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return SwitchToNextInputMethod();
6775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
6785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  std::vector<std::string>::const_iterator iter =
68003b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)      std::find(active_input_method_ids.begin(),
68103b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)                active_input_method_ids.end(),
68203b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)                previous_input_method.id());
68303b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  if (iter == active_input_method_ids.end()) {
68403b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)    // previous_input_method is not supported.
6855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return SwitchToNextInputMethod();
6865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
68703b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  ChangeInputMethod(*iter, true);
68803b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)
6895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return true;
6905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
6915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
69203b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)bool InputMethodManagerImpl::StateImpl::SwitchInputMethod(
6935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const ui::Accelerator& accelerator) {
6945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Sanity check.
69503b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  if (active_input_method_ids.empty()) {
6965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    DVLOG(1) << "active input method is empty";
6975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;
6985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
6995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
7005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Get the list of input method ids for the |accelerator|. For example, get
7015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // { "mozc-hangul", "xkb:kr:kr104:kor" } for ui::VKEY_DBE_SBCSCHAR.
7025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  std::vector<std::string> input_method_ids_to_switch;
7035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  switch (accelerator.key_code()) {
7045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    case ui::VKEY_CONVERT:  // Henkan key on JP106 keyboard
70546d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)      input_method_ids_to_switch.push_back(
70646d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)          extension_ime_util::GetInputMethodIDByEngineID("nacl_mozc_jp"));
7075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      break;
7085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    case ui::VKEY_NONCONVERT:  // Muhenkan key on JP106 keyboard
70946d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)      input_method_ids_to_switch.push_back(
71046d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)          extension_ime_util::GetInputMethodIDByEngineID("xkb:jp::jpn"));
7115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      break;
7125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    case ui::VKEY_DBE_SBCSCHAR:  // ZenkakuHankaku key on JP106 keyboard
7135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    case ui::VKEY_DBE_DBCSCHAR:
71446d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)      input_method_ids_to_switch.push_back(
71546d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)          extension_ime_util::GetInputMethodIDByEngineID("nacl_mozc_jp"));
71646d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)      input_method_ids_to_switch.push_back(
71746d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)          extension_ime_util::GetInputMethodIDByEngineID("xkb:jp::jpn"));
7185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      break;
7195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    default:
7205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      NOTREACHED();
7215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      break;
7225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
7235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (input_method_ids_to_switch.empty()) {
7245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    DVLOG(1) << "Unexpected VKEY: " << accelerator.key_code();
7255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;
7265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
7275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
7285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Obtain the intersection of input_method_ids_to_switch and
72903b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  // active_input_method_ids. The order of IDs in active_input_method_ids is
7305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // preserved.
7315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  std::vector<std::string> ids;
7325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  for (size_t i = 0; i < input_method_ids_to_switch.size(); ++i) {
7335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const std::string& id = input_method_ids_to_switch[i];
73403b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)    if (Contains(active_input_method_ids, id))
7355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      ids.push_back(id);
7365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
7375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (ids.empty()) {
7385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // No input method for the accelerator is active. For example, we should
7395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // just ignore VKEY_HANGUL when mozc-hangul is not active.
7405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;
7415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
7425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
74303b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  SwitchToNextInputMethodInternal(ids, current_input_method.id());
7445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return true;  // consume the accelerator.
7455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
7465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
74703b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)void InputMethodManagerImpl::StateImpl::SwitchToNextInputMethodInternal(
7485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const std::vector<std::string>& input_method_ids,
74903b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)    const std::string& current_input_methodid) {
75003b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  std::vector<std::string>::const_iterator iter = std::find(
75103b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)      input_method_ids.begin(), input_method_ids.end(), current_input_methodid);
7525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (iter != input_method_ids.end())
7535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    ++iter;
7545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (iter == input_method_ids.end())
7555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    iter = input_method_ids.begin();
75603b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  ChangeInputMethod(*iter, true);
7575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
7585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
75903b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)InputMethodDescriptor InputMethodManagerImpl::StateImpl::GetCurrentInputMethod()
76003b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)    const {
76103b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  if (current_input_method.id().empty())
762c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    return InputMethodUtil::GetFallbackInputMethodDescriptor();
7635d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
76403b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  return current_input_method;
76503b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)}
76603b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)
76703b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)bool InputMethodManagerImpl::StateImpl::InputMethodIsActivated(
76803b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)    const std::string& input_method_id) const {
76903b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  return Contains(active_input_method_ids, input_method_id);
77003b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)}
77103b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)
77203b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)// ------------------------ InputMethodManagerImpl
77303b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)bool InputMethodManagerImpl::IsLoginKeyboard(
77403b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)    const std::string& layout) const {
77503b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  return util_.IsLoginKeyboard(layout);
77603b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)}
77703b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)
77803b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)bool InputMethodManagerImpl::MigrateInputMethods(
77903b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)    std::vector<std::string>* input_method_ids) {
78003b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  return util_.MigrateInputMethods(input_method_ids);
78103b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)}
78203b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)
78303b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)// Starts or stops the system input method framework as needed.
78403b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)void InputMethodManagerImpl::ReconfigureIMFramework(
78503b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)    InputMethodManagerImpl::StateImpl* state) {
78603b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  LoadNecessaryComponentExtensions(state);
78703b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)
78803b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  // Initialize candidate window controller and widgets such as
78903b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  // candidate window, infolist and mode indicator.  Note, mode
79003b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  // indicator is used by only keyboard layout input methods.
79103b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  if (state_.get() == state)
79203b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)    MaybeInitializeCandidateWindowController();
79303b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)}
79403b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)
79503b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)void InputMethodManagerImpl::SetState(
79603b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)    scoped_refptr<InputMethodManager::State> state) {
7971320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  DCHECK(state.get());
79803b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  InputMethodManagerImpl::StateImpl* new_impl_state =
79903b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)      static_cast<InputMethodManagerImpl::StateImpl*>(state.get());
80003b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  const bool need_update_current_input_method =
8011320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci      (state_.get()
8021320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci           ? state_->current_input_method.id() !=
8031320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci                 new_impl_state->current_input_method.id()
8041320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci           : true);
80503b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  state_ = new_impl_state;
80603b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)
8071320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  if (state_.get() && state_->active_input_method_ids.size()) {
80803b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)    // Initialize candidate window controller and widgets such as
80903b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)    // candidate window, infolist and mode indicator.  Note, mode
81003b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)    // indicator is used by only keyboard layout input methods.
81103b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)    MaybeInitializeCandidateWindowController();
81203b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)
81303b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)    if (need_update_current_input_method) {
81403b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)      ChangeInputMethodInternal(state_->current_input_method,
81503b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)                                false /* show_message */,
81603b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)                                true /* notify_menu */);
81703b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)    } else {
81803b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)      // Update input method indicators (e.g. "US", "DV") in Chrome windows.
81903b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)      FOR_EACH_OBSERVER(InputMethodManager::Observer,
82003b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)                        observers_,
82103b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)                        InputMethodChanged(this, false /* show_message */));
82203b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)    }
82303b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  }
82403b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)}
82503b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)
82603b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)scoped_refptr<InputMethodManager::State>
82703b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)InputMethodManagerImpl::GetActiveIMEState() {
82803b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  return scoped_refptr<InputMethodManager::State>(state_.get());
82903b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)}
83003b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)
83103b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)InputMethodManagerImpl::InputMethodManagerImpl(
83203b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)    scoped_ptr<InputMethodDelegate> delegate,
83303b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)    bool enable_extension_loading)
83403b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)    : delegate_(delegate.Pass()),
83503b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)      ui_session_(STATE_LOGIN_SCREEN),
83603b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)      state_(NULL),
83703b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)      util_(delegate_.get()),
83803b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)      component_extension_ime_manager_(new ComponentExtensionIMEManager()),
83903b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)      enable_extension_loading_(enable_extension_loading) {
84003b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  if (base::SysInfo::IsRunningOnChromeOS())
84103b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)    keyboard_.reset(ImeKeyboard::Create());
84203b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  else
84303b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)    keyboard_.reset(new FakeImeKeyboard());
84403b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)
84503b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  // Initializes the system IME list.
84603b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  scoped_ptr<ComponentExtensionIMEManagerDelegate> comp_delegate(
84703b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)      new ComponentExtensionIMEManagerImpl());
84803b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  component_extension_ime_manager_->Initialize(comp_delegate.Pass());
8491320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  const InputMethodDescriptors& descriptors =
8501320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci      component_extension_ime_manager_->GetAllIMEAsInputMethodDescriptor();
8511320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  util_.ResetInputMethods(descriptors);
8521320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
8531320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  // Initializes the stat id map.
8541320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  std::map<int, std::vector<std::string> > buckets;
8551320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  for (InputMethodDescriptors::const_iterator it = descriptors.begin();
8561320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci       it != descriptors.end(); ++it) {
8571320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    char first_char;
8581320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    int cat_id = static_cast<int>(
8591320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci        GetInputMethodCategory(it->id(), &first_char));
8601320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    int key = cat_id * 1000 + first_char;
8611320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    buckets[key].push_back(it->id());
8621320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  }
8631320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  for (std::map<int, std::vector<std::string>>::iterator i =
8641320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci       buckets.begin(); i != buckets.end(); ++i) {
8651320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    std::sort(i->second.begin(), i->second.end());
8661320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    for (size_t j = 0; j < i->second.size() && j < 100; ++j) {
8671320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci      int key = i->first * 100 + j;
8681320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci      stat_id_map_[i->second[j]] = key;
8691320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    }
8701320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  }
87103b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)}
87203b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)
87303b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)InputMethodManagerImpl::~InputMethodManagerImpl() {
87403b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  if (candidate_window_controller_.get())
87503b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)    candidate_window_controller_->RemoveObserver(this);
87603b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)}
87703b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)
8781320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tuccivoid InputMethodManagerImpl::RecordInputMethodUsage(
8791320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    std::string input_method_id) {
8801320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  UMA_HISTOGRAM_ENUMERATION("InputMethod.Category",
8811320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci                            GetInputMethodCategory(input_method_id),
8821320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci                            INPUT_METHOD_CATEGORY_MAX);
8831320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  UMA_HISTOGRAM_SPARSE_SLOWLY("InputMethod.ID",
8841320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci                              stat_id_map_[input_method_id]);
8851320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci}
8861320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
88703b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)void InputMethodManagerImpl::AddObserver(
88803b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)    InputMethodManager::Observer* observer) {
88903b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  observers_.AddObserver(observer);
89003b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)}
89103b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)
89203b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)void InputMethodManagerImpl::AddCandidateWindowObserver(
89303b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)    InputMethodManager::CandidateWindowObserver* observer) {
89403b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  candidate_window_observers_.AddObserver(observer);
89503b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)}
89603b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)
89703b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)void InputMethodManagerImpl::RemoveObserver(
89803b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)    InputMethodManager::Observer* observer) {
89903b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  observers_.RemoveObserver(observer);
90003b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)}
90103b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)
90203b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)void InputMethodManagerImpl::RemoveCandidateWindowObserver(
90303b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)    InputMethodManager::CandidateWindowObserver* observer) {
90403b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  candidate_window_observers_.RemoveObserver(observer);
90503b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)}
90603b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)
90703b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)InputMethodManager::UISessionState InputMethodManagerImpl::GetUISessionState() {
90803b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  return ui_session_;
90903b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)}
91003b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)
91103b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)void InputMethodManagerImpl::SetUISessionState(UISessionState new_ui_session) {
91203b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  ui_session_ = new_ui_session;
91303b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  switch (ui_session_) {
91403b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)    case STATE_LOGIN_SCREEN:
91503b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)      break;
91603b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)    case STATE_BROWSER_SCREEN:
91703b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)      break;
91803b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)    case STATE_LOCK_SCREEN:
91903b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)      break;
92003b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)    case STATE_TERMINATING: {
92103b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)      if (candidate_window_controller_.get())
92203b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)        candidate_window_controller_.reset();
92303b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)      break;
92403b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)    }
92503b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  }
92603b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)}
92703b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)
92803b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)scoped_ptr<InputMethodDescriptors>
92903b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)InputMethodManagerImpl::GetSupportedInputMethods() const {
93003b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  return scoped_ptr<InputMethodDescriptors>(new InputMethodDescriptors).Pass();
93103b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)}
93203b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)
93303b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)const InputMethodDescriptor* InputMethodManagerImpl::LookupInputMethod(
93403b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)    const std::string& input_method_id,
93503b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)    InputMethodManagerImpl::StateImpl* state) {
93603b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  DCHECK(state);
93703b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)
93803b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  std::string input_method_id_to_switch = input_method_id;
93903b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)
94003b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  // Sanity check
94103b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  if (!state->InputMethodIsActivated(input_method_id)) {
94203b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)    scoped_ptr<InputMethodDescriptors> input_methods(
94303b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)        state->GetActiveInputMethods());
94403b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)    DCHECK(!input_methods->empty());
94503b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)    input_method_id_to_switch = input_methods->at(0).id();
94603b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)    if (!input_method_id.empty()) {
94703b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)      DVLOG(1) << "Can't change the current input method to "
94803b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)               << input_method_id << " since the engine is not enabled. "
94903b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)               << "Switch to " << input_method_id_to_switch << " instead.";
95003b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)    }
95103b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  }
95203b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)
95303b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  const InputMethodDescriptor* descriptor = NULL;
95403b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  if (extension_ime_util::IsExtensionIME(input_method_id_to_switch)) {
95503b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)    DCHECK(state->extra_input_methods.find(input_method_id_to_switch) !=
95603b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)           state->extra_input_methods.end());
95703b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)    descriptor = &(state->extra_input_methods[input_method_id_to_switch]);
95803b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  } else {
95903b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)    descriptor =
96003b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)        util_.GetInputMethodDescriptorFromId(input_method_id_to_switch);
96103b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)    if (!descriptor)
96203b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)      LOG(ERROR) << "Unknown input method id: " << input_method_id_to_switch;
96303b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  }
96403b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  DCHECK(descriptor);
96503b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  return descriptor;
96603b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)}
96703b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)
96803b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)void InputMethodManagerImpl::ChangeInputMethodInternal(
96903b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)    const InputMethodDescriptor& descriptor,
97003b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)    bool show_message,
97103b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)    bool notify_menu) {
97203b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  // No need to switch input method when terminating.
97303b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  if (ui_session_ == STATE_TERMINATING)
97403b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)    return;
97503b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)
97603b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  if (candidate_window_controller_.get())
97703b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)    candidate_window_controller_->Hide();
97803b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)
97903b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  if (notify_menu) {
98003b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)    // Clear property list.  Property list would be updated by
98103b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)    // extension IMEs via InputMethodEngine::(Set|Update)MenuItems.
98203b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)    // If the current input method is a keyboard layout, empty
98303b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)    // properties are sufficient.
98403b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)    const ash::ime::InputMethodMenuItemList empty_menu_item_list;
98503b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)    ash::ime::InputMethodMenuManager* input_method_menu_manager =
98603b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)        ash::ime::InputMethodMenuManager::GetInstance();
98703b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)    input_method_menu_manager->SetCurrentInputMethodMenuItemList(
98803b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)            empty_menu_item_list);
98903b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  }
99003b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)
99103b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  // Disable the current engine handler.
99203b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  IMEEngineHandlerInterface* engine =
99303b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)      IMEBridge::Get()->GetCurrentEngineHandler();
99403b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  if (engine)
99503b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)    engine->Disable();
99603b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)
99703b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  // Configure the next engine handler.
99803b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  // This must be after |current_input_method| has been set to new input
99903b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  // method, because engine's Enable() method needs to access it.
100003b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  const std::string& extension_id =
100103b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)      extension_ime_util::GetExtensionIDFromInputMethodID(descriptor.id());
100203b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  const std::string& component_id =
100303b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)      extension_ime_util::GetComponentIDByInputMethodID(descriptor.id());
100403b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  engine = engine_map_[extension_id];
100503b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)
100603b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  IMEBridge::Get()->SetCurrentEngineHandler(engine);
100703b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)
10081320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  if (engine) {
100903b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)    engine->Enable(component_id);
10101320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  } else {
10111320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    // If no engine to enable, cancel the virtual keyboard url override so that
10121320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    // it can use the fallback system virtual keyboard UI.
10131320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    keyboard::SetOverrideContentUrl(GURL());
10141320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    keyboard::KeyboardController* keyboard_controller =
10151320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci        keyboard::KeyboardController::GetInstance();
10161320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    if (keyboard_controller)
10171320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci      keyboard_controller->Reload();
10181320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  }
101903b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)
102003b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  // Change the keyboard layout to a preferred layout for the input method.
102103b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  if (!keyboard_->SetCurrentKeyboardLayoutByName(
102203b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)          descriptor.GetPreferredKeyboardLayout())) {
102303b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)    LOG(ERROR) << "Failed to change keyboard layout to "
102403b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)               << descriptor.GetPreferredKeyboardLayout();
102503b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  }
102603b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)
102703b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  // Update input method indicators (e.g. "US", "DV") in Chrome windows.
102803b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  FOR_EACH_OBSERVER(InputMethodManager::Observer,
102903b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)                    observers_,
103003b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)                    InputMethodChanged(this, show_message));
103103b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)}
103203b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)
103303b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)void InputMethodManagerImpl::LoadNecessaryComponentExtensions(
103403b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)    InputMethodManagerImpl::StateImpl* state) {
103503b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  // Load component extensions but also update |active_input_method_ids| as
103603b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  // some component extension IMEs may have been removed from the Chrome OS
103703b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  // image. If specified component extension IME no longer exists, falling back
103803b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  // to an existing IME.
103903b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  DCHECK(state);
104003b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  std::vector<std::string> unfiltered_input_method_ids;
104103b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  unfiltered_input_method_ids.swap(state->active_input_method_ids);
104203b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  for (size_t i = 0; i < unfiltered_input_method_ids.size(); ++i) {
104303b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)    if (!extension_ime_util::IsComponentExtensionIME(
104403b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)        unfiltered_input_method_ids[i])) {
104503b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)      // Legacy IMEs or xkb layouts are alwayes active.
104603b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)      state->active_input_method_ids.push_back(unfiltered_input_method_ids[i]);
104703b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)    } else if (component_extension_ime_manager_->IsWhitelisted(
104803b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)        unfiltered_input_method_ids[i])) {
104903b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)      if (enable_extension_loading_) {
105003b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)        component_extension_ime_manager_->LoadComponentExtensionIME(
105103b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)            state->profile, unfiltered_input_method_ids[i]);
105203b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)      }
105303b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)
105403b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)      state->active_input_method_ids.push_back(unfiltered_input_method_ids[i]);
105503b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)    }
105603b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  }
105703b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)}
105803b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)
105903b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)void InputMethodManagerImpl::ActivateInputMethodMenuItem(
106003b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)    const std::string& key) {
106103b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  DCHECK(!key.empty());
106203b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)
106303b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  if (ash::ime::InputMethodMenuManager::GetInstance()->
106403b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)      HasInputMethodMenuItemForKey(key)) {
106503b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)    IMEEngineHandlerInterface* engine =
106603b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)        IMEBridge::Get()->GetCurrentEngineHandler();
106703b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)    if (engine)
106803b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)      engine->PropertyActivate(key);
106903b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)    return;
107003b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  }
107103b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)
107203b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  DVLOG(1) << "ActivateInputMethodMenuItem: unknown key: " << key;
10735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
10745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1075effb81e5f8246d0db0270817048dc992db66e9fbBen Murdochbool InputMethodManagerImpl::IsISOLevel5ShiftUsedByCurrentInputMethod() const {
1076a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch  return keyboard_->IsISOLevel5ShiftAvailable();
1077effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch}
1078effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch
1079effb81e5f8246d0db0270817048dc992db66e9fbBen Murdochbool InputMethodManagerImpl::IsAltGrUsedByCurrentInputMethod() const {
1080a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch  return keyboard_->IsAltGrAvailable();
1081effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch}
1082effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch
1083a02191e04bc25c4935f804f2c080ae28663d096dBen MurdochImeKeyboard* InputMethodManagerImpl::GetImeKeyboard() {
1084a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch  return keyboard_.get();
10855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
10865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
10875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)InputMethodUtil* InputMethodManagerImpl::GetInputMethodUtil() {
10885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return &util_;
10895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
10905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1091c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)ComponentExtensionIMEManager*
1092c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    InputMethodManagerImpl::GetComponentExtensionIMEManager() {
1093c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  return component_extension_ime_manager_.get();
1094c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)}
1095c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
109603b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)scoped_refptr<InputMethodManager::State> InputMethodManagerImpl::CreateNewState(
109703b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)    Profile* profile) {
109803b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  return scoped_refptr<InputMethodManager::State>(new StateImpl(this, profile));
109903b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)}
110003b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)
11015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void InputMethodManagerImpl::SetCandidateWindowControllerForTesting(
11025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    CandidateWindowController* candidate_window_controller) {
11035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  candidate_window_controller_.reset(candidate_window_controller);
11045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  candidate_window_controller_->AddObserver(this);
11055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
11065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1107a02191e04bc25c4935f804f2c080ae28663d096dBen Murdochvoid InputMethodManagerImpl::SetImeKeyboardForTesting(ImeKeyboard* keyboard) {
1108a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch  keyboard_.reset(keyboard);
11095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
11105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1111c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)void InputMethodManagerImpl::InitializeComponentExtensionForTesting(
1112c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    scoped_ptr<ComponentExtensionIMEManagerDelegate> delegate) {
11135f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  component_extension_ime_manager_->Initialize(delegate.Pass());
11145f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  util_.ResetInputMethods(
11155f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)      component_extension_ime_manager_->GetAllIMEAsInputMethodDescriptor());
1116c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)}
1117c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
1118a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)void InputMethodManagerImpl::CandidateClicked(int index) {
11195d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  IMEEngineHandlerInterface* engine =
11205d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      IMEBridge::Get()->GetCurrentEngineHandler();
1121a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  if (engine)
1122a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)    engine->CandidateClicked(index);
1123a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)}
1124a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)
11255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void InputMethodManagerImpl::CandidateWindowOpened() {
11265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  FOR_EACH_OBSERVER(InputMethodManager::CandidateWindowObserver,
11275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                    candidate_window_observers_,
11285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                    CandidateWindowOpened(this));
11295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
11305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
11315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void InputMethodManagerImpl::CandidateWindowClosed() {
11325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  FOR_EACH_OBSERVER(InputMethodManager::CandidateWindowObserver,
11335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                    candidate_window_observers_,
11345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                    CandidateWindowClosed(this));
11355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
11365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
11375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void InputMethodManagerImpl::MaybeInitializeCandidateWindowController() {
11385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (candidate_window_controller_.get())
11395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
11405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
11415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  candidate_window_controller_.reset(
11425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      CandidateWindowController::CreateCandidateWindowController());
1143a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  candidate_window_controller_->AddObserver(this);
11445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
11455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
11465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}  // namespace input_method
11475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}  // namespace chromeos
1148