Home | History | Annotate | Download | only in input_method
      1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
      2 // Use of this source code is governed by a BSD-style license that can be
      3 // found in the LICENSE file.
      4 
      5 #include "chrome/browser/chromeos/input_method/input_method_manager_impl.h"
      6 
      7 #include <algorithm>  // std::find
      8 
      9 #include <sstream>
     10 
     11 #include "ash/ime/input_method_menu_item.h"
     12 #include "ash/ime/input_method_menu_manager.h"
     13 #include "base/basictypes.h"
     14 #include "base/bind.h"
     15 #include "base/location.h"
     16 #include "base/memory/scoped_ptr.h"
     17 #include "base/metrics/histogram.h"
     18 #include "base/metrics/sparse_histogram.h"
     19 #include "base/prefs/pref_service.h"
     20 #include "base/strings/string_split.h"
     21 #include "base/strings/string_util.h"
     22 #include "base/strings/stringprintf.h"
     23 #include "base/sys_info.h"
     24 #include "chrome/browser/browser_process.h"
     25 #include "chrome/browser/chromeos/input_method/candidate_window_controller.h"
     26 #include "chrome/browser/chromeos/input_method/component_extension_ime_manager_impl.h"
     27 #include "chrome/browser/chromeos/input_method/input_method_engine.h"
     28 #include "chrome/browser/chromeos/language_preferences.h"
     29 #include "chrome/browser/chromeos/login/session/user_session_manager.h"
     30 #include "chrome/browser/chromeos/profiles/profile_helper.h"
     31 #include "chrome/browser/profiles/profile_manager.h"
     32 #include "chrome/common/pref_names.h"
     33 #include "chromeos/ime/component_extension_ime_manager.h"
     34 #include "chromeos/ime/extension_ime_util.h"
     35 #include "chromeos/ime/fake_ime_keyboard.h"
     36 #include "chromeos/ime/ime_keyboard.h"
     37 #include "chromeos/ime/input_method_delegate.h"
     38 #include "components/user_manager/user_manager.h"
     39 #include "third_party/icu/source/common/unicode/uloc.h"
     40 #include "ui/base/accelerators/accelerator.h"
     41 #include "ui/keyboard/keyboard_controller.h"
     42 #include "ui/keyboard/keyboard_util.h"
     43 
     44 namespace chromeos {
     45 namespace input_method {
     46 
     47 namespace {
     48 
     49 bool Contains(const std::vector<std::string>& container,
     50               const std::string& value) {
     51   return std::find(container.begin(), container.end(), value) !=
     52       container.end();
     53 }
     54 
     55 enum InputMethodCategory {
     56   INPUT_METHOD_CATEGORY_UNKNOWN = 0,
     57   INPUT_METHOD_CATEGORY_XKB,  // XKB input methods
     58   INPUT_METHOD_CATEGORY_ZH,   // Chinese input methods
     59   INPUT_METHOD_CATEGORY_JA,   // Japanese input methods
     60   INPUT_METHOD_CATEGORY_KO,   // Korean input methods
     61   INPUT_METHOD_CATEGORY_M17N, // Multilingualization input methods
     62   INPUT_METHOD_CATEGORY_T13N, // Transliteration input methods
     63   INPUT_METHOD_CATEGORY_MAX
     64 };
     65 
     66 InputMethodCategory GetInputMethodCategory(const std::string& input_method_id,
     67                                            char* first_char = NULL) {
     68   const std::string component_id =
     69       extension_ime_util::GetComponentIDByInputMethodID(input_method_id);
     70   InputMethodCategory category = INPUT_METHOD_CATEGORY_UNKNOWN;
     71   char ch = 0;
     72   if (StartsWithASCII(component_id, "xkb:", true)) {
     73     ch = component_id[4];
     74     category = INPUT_METHOD_CATEGORY_XKB;
     75   } else if (StartsWithASCII(component_id, "zh-", true)) {
     76     size_t pos = component_id.find("-t-i0-");
     77     if (pos > 0)
     78       pos += 6;
     79     ch = component_id[pos];
     80     category = INPUT_METHOD_CATEGORY_ZH;
     81   } else if (StartsWithASCII(component_id, "nacl_mozc_", true)) {
     82     ch = component_id[10];
     83     category = INPUT_METHOD_CATEGORY_JA;
     84   } else if (StartsWithASCII(component_id, "hangul_", true)) {
     85     ch = component_id[7];
     86     category = INPUT_METHOD_CATEGORY_KO;
     87   } else if (StartsWithASCII(component_id, "vkd_", true)) {
     88     ch = component_id[4];
     89     category = INPUT_METHOD_CATEGORY_M17N;
     90   } else if (component_id.find("-t-i0-") > 0) {
     91     ch = component_id[0];
     92     category = INPUT_METHOD_CATEGORY_T13N;
     93   }
     94 
     95   if (first_char)
     96     *first_char = ch;
     97   return category;
     98 }
     99 
    100 }  // namespace
    101 
    102 // ------------------------ InputMethodManagerImpl::StateImpl
    103 
    104 InputMethodManagerImpl::StateImpl::StateImpl(InputMethodManagerImpl* manager,
    105                                              Profile* profile)
    106     : profile(profile), manager_(manager) {
    107 }
    108 
    109 InputMethodManagerImpl::StateImpl::~StateImpl() {
    110 }
    111 
    112 void InputMethodManagerImpl::StateImpl::InitFrom(const StateImpl& other) {
    113   previous_input_method = other.previous_input_method;
    114   current_input_method = other.current_input_method;
    115 
    116   active_input_method_ids = other.active_input_method_ids;
    117 
    118   pending_input_method_id = other.pending_input_method_id;
    119 
    120   enabled_extension_imes = other.enabled_extension_imes;
    121   extra_input_methods = other.extra_input_methods;
    122 }
    123 
    124 bool InputMethodManagerImpl::StateImpl::IsActive() const {
    125   return manager_->state_.get() == this;
    126 }
    127 
    128 std::string InputMethodManagerImpl::StateImpl::Dump() const {
    129   std::ostringstream os;
    130 
    131   os << "################# "
    132      << (profile ? profile->GetProfileName() : std::string("NULL"))
    133      << " #################\n";
    134 
    135   os << "previous_input_method: '"
    136      << previous_input_method.GetPreferredKeyboardLayout() << "'\n";
    137   os << "current_input_method: '"
    138      << current_input_method.GetPreferredKeyboardLayout() << "'\n";
    139   os << "active_input_method_ids (size=" << active_input_method_ids.size()
    140      << "):";
    141   for (size_t i = 0; i < active_input_method_ids.size(); ++i) {
    142     os << " '" << active_input_method_ids[i] << "',";
    143   }
    144   os << "\n";
    145   os << "enabled_extension_imes (size=" << enabled_extension_imes.size()
    146      << "):";
    147   for (size_t i = 0; i < enabled_extension_imes.size(); ++i) {
    148     os << " '" << enabled_extension_imes[i] << "'\n";
    149   }
    150   os << "\n";
    151   os << "extra_input_methods (size=" << extra_input_methods.size() << "):";
    152   for (std::map<std::string, InputMethodDescriptor>::const_iterator it =
    153            extra_input_methods.begin();
    154        it != extra_input_methods.end();
    155        ++it) {
    156     os << " '" << it->first << "' => '" << it->second.id() << "',\n";
    157   }
    158   os << "pending_input_method_id: '" << pending_input_method_id << "'\n";
    159 
    160   return os.str();
    161 }
    162 
    163 scoped_refptr<InputMethodManager::State>
    164 InputMethodManagerImpl::StateImpl::Clone() const {
    165   scoped_refptr<StateImpl> new_state(new StateImpl(this->manager_, profile));
    166   new_state->InitFrom(*this);
    167   return scoped_refptr<InputMethodManager::State>(new_state.get());
    168 }
    169 
    170 scoped_ptr<InputMethodDescriptors>
    171 InputMethodManagerImpl::StateImpl::GetActiveInputMethods() const {
    172   scoped_ptr<InputMethodDescriptors> result(new InputMethodDescriptors);
    173   // Build the active input method descriptors from the active input
    174   // methods cache |active_input_method_ids|.
    175   for (size_t i = 0; i < active_input_method_ids.size(); ++i) {
    176     const std::string& input_method_id = active_input_method_ids[i];
    177     const InputMethodDescriptor* descriptor =
    178         manager_->util_.GetInputMethodDescriptorFromId(input_method_id);
    179     if (descriptor) {
    180       result->push_back(*descriptor);
    181     } else {
    182       std::map<std::string, InputMethodDescriptor>::const_iterator ix =
    183           extra_input_methods.find(input_method_id);
    184       if (ix != extra_input_methods.end())
    185         result->push_back(ix->second);
    186       else
    187         DVLOG(1) << "Descriptor is not found for: " << input_method_id;
    188     }
    189   }
    190   if (result->empty()) {
    191     // Initially |active_input_method_ids| is empty. browser_tests might take
    192     // this path.
    193     result->push_back(
    194         InputMethodUtil::GetFallbackInputMethodDescriptor());
    195   }
    196   return result.Pass();
    197 }
    198 
    199 const std::vector<std::string>&
    200 InputMethodManagerImpl::StateImpl::GetActiveInputMethodIds() const {
    201   return active_input_method_ids;
    202 }
    203 
    204 size_t InputMethodManagerImpl::StateImpl::GetNumActiveInputMethods() const {
    205   return active_input_method_ids.size();
    206 }
    207 
    208 const InputMethodDescriptor*
    209 InputMethodManagerImpl::StateImpl::GetInputMethodFromId(
    210     const std::string& input_method_id) const {
    211   const InputMethodDescriptor* ime =
    212       manager_->util_.GetInputMethodDescriptorFromId(input_method_id);
    213   if (!ime) {
    214     std::map<std::string, InputMethodDescriptor>::const_iterator ix =
    215         extra_input_methods.find(input_method_id);
    216     if (ix != extra_input_methods.end())
    217       ime = &ix->second;
    218   }
    219   return ime;
    220 }
    221 
    222 void InputMethodManagerImpl::StateImpl::EnableLoginLayouts(
    223     const std::string& language_code,
    224     const std::vector<std::string>& initial_layouts) {
    225   if (manager_->ui_session_ == STATE_TERMINATING)
    226     return;
    227 
    228   // First, hardware keyboard layout should be shown.
    229   std::vector<std::string> candidates =
    230       manager_->util_.GetHardwareLoginInputMethodIds();
    231 
    232   // Second, locale based input method should be shown.
    233   // Add input methods associated with the language.
    234   std::vector<std::string> layouts_from_locale;
    235   manager_->util_.GetInputMethodIdsFromLanguageCode(
    236       language_code, kKeyboardLayoutsOnly, &layouts_from_locale);
    237   candidates.insert(candidates.end(), layouts_from_locale.begin(),
    238                     layouts_from_locale.end());
    239 
    240   std::vector<std::string> layouts;
    241   // First, add the initial input method ID, if it's requested, to
    242   // layouts, so it appears first on the list of active input
    243   // methods at the input language status menu.
    244   for (size_t i = 0; i < initial_layouts.size(); ++i) {
    245     if (manager_->util_.IsValidInputMethodId(initial_layouts[i])) {
    246       if (manager_->IsLoginKeyboard(initial_layouts[i])) {
    247         layouts.push_back(initial_layouts[i]);
    248       } else {
    249         DVLOG(1)
    250             << "EnableLoginLayouts: ignoring non-login initial keyboard layout:"
    251             << initial_layouts[i];
    252       }
    253     } else if (!initial_layouts[i].empty()) {
    254       DVLOG(1) << "EnableLoginLayouts: ignoring non-keyboard or invalid ID: "
    255                << initial_layouts[i];
    256     }
    257   }
    258 
    259   // Add candidates to layouts, while skipping duplicates.
    260   for (size_t i = 0; i < candidates.size(); ++i) {
    261     const std::string& candidate = candidates[i];
    262     // Not efficient, but should be fine, as the two vectors are very
    263     // short (2-5 items).
    264     if (!Contains(layouts, candidate) && manager_->IsLoginKeyboard(candidate))
    265       layouts.push_back(candidate);
    266   }
    267 
    268   manager_->MigrateInputMethods(&layouts);
    269   active_input_method_ids.swap(layouts);
    270 
    271   if (IsActive()) {
    272     // Initialize candidate window controller and widgets such as
    273     // candidate window, infolist and mode indicator.  Note, mode
    274     // indicator is used by only keyboard layout input methods.
    275     if (active_input_method_ids.size() > 1)
    276       manager_->MaybeInitializeCandidateWindowController();
    277 
    278     // you can pass empty |initial_layout|.
    279     ChangeInputMethod(initial_layouts.empty()
    280                           ? std::string()
    281                           : extension_ime_util::GetInputMethodIDByEngineID(
    282                                 initial_layouts[0]),
    283                       false);
    284   }
    285 }
    286 
    287 void InputMethodManagerImpl::StateImpl::EnableLockScreenLayouts() {
    288   std::set<std::string> added_ids;
    289 
    290   const std::vector<std::string>& hardware_keyboard_ids =
    291       manager_->util_.GetHardwareLoginInputMethodIds();
    292 
    293   std::vector<std::string> new_active_input_method_ids;
    294   for (size_t i = 0; i < active_input_method_ids.size(); ++i) {
    295     const std::string& input_method_id = active_input_method_ids[i];
    296     // Skip if it's not a keyboard layout. Drop input methods including
    297     // extension ones.
    298     if (!manager_->IsLoginKeyboard(input_method_id) ||
    299         added_ids.count(input_method_id)) {
    300       continue;
    301     }
    302     new_active_input_method_ids.push_back(input_method_id);
    303     added_ids.insert(input_method_id);
    304   }
    305 
    306   // We'll add the hardware keyboard if it's not included in
    307   // |active_input_method_ids| so that the user can always use the hardware
    308   // keyboard on the screen locker.
    309   for (size_t i = 0; i < hardware_keyboard_ids.size(); ++i) {
    310     if (added_ids.count(hardware_keyboard_ids[i]))
    311       continue;
    312     new_active_input_method_ids.push_back(hardware_keyboard_ids[i]);
    313     added_ids.insert(hardware_keyboard_ids[i]);
    314   }
    315 
    316   active_input_method_ids.swap(new_active_input_method_ids);
    317 
    318   // Re-check current_input_method.
    319   ChangeInputMethod(current_input_method.id(), false);
    320 }
    321 
    322 // Adds new input method to given list.
    323 bool InputMethodManagerImpl::StateImpl::EnableInputMethodImpl(
    324     const std::string& input_method_id,
    325     std::vector<std::string>* new_active_input_method_ids) const {
    326   DCHECK(new_active_input_method_ids);
    327   if (!manager_->util_.IsValidInputMethodId(input_method_id)) {
    328     DVLOG(1) << "EnableInputMethod: Invalid ID: " << input_method_id;
    329     return false;
    330   }
    331 
    332   if (!Contains(*new_active_input_method_ids, input_method_id))
    333     new_active_input_method_ids->push_back(input_method_id);
    334 
    335   return true;
    336 }
    337 
    338 bool InputMethodManagerImpl::StateImpl::EnableInputMethod(
    339     const std::string& input_method_id) {
    340   if (!EnableInputMethodImpl(input_method_id, &active_input_method_ids))
    341     return false;
    342 
    343   manager_->ReconfigureIMFramework(this);
    344   return true;
    345 }
    346 
    347 bool InputMethodManagerImpl::StateImpl::ReplaceEnabledInputMethods(
    348     const std::vector<std::string>& new_active_input_method_ids) {
    349   if (manager_->ui_session_ == STATE_TERMINATING)
    350     return false;
    351 
    352   // Filter unknown or obsolete IDs.
    353   std::vector<std::string> new_active_input_method_ids_filtered;
    354 
    355   for (size_t i = 0; i < new_active_input_method_ids.size(); ++i)
    356     EnableInputMethodImpl(new_active_input_method_ids[i],
    357                           &new_active_input_method_ids_filtered);
    358 
    359   if (new_active_input_method_ids_filtered.empty()) {
    360     DVLOG(1) << "ReplaceEnabledInputMethods: No valid input method ID";
    361     return false;
    362   }
    363 
    364   // Copy extension IDs to |new_active_input_method_ids_filtered|. We have to
    365   // keep relative order of the extension input method IDs.
    366   for (size_t i = 0; i < active_input_method_ids.size(); ++i) {
    367     const std::string& input_method_id = active_input_method_ids[i];
    368     if (extension_ime_util::IsExtensionIME(input_method_id))
    369       new_active_input_method_ids_filtered.push_back(input_method_id);
    370   }
    371   active_input_method_ids.swap(new_active_input_method_ids_filtered);
    372   manager_->MigrateInputMethods(&active_input_method_ids);
    373 
    374   manager_->ReconfigureIMFramework(this);
    375 
    376   // If |current_input_method| is no longer in |active_input_method_ids|,
    377   // ChangeInputMethod() picks the first one in |active_input_method_ids|.
    378   ChangeInputMethod(current_input_method.id(), false);
    379 
    380   // Record histogram for active input method count.
    381   UMA_HISTOGRAM_COUNTS("InputMethod.ActiveCount",
    382                        active_input_method_ids.size());
    383 
    384   return true;
    385 }
    386 
    387 void InputMethodManagerImpl::StateImpl::ChangeInputMethod(
    388     const std::string& input_method_id,
    389     bool show_message) {
    390   if (manager_->ui_session_ == STATE_TERMINATING)
    391     return;
    392 
    393   bool notify_menu = false;
    394   // For 3rd party IME, when the user just logged in, SetEnabledExtensionImes
    395   // happens after activating the 3rd party IME.
    396   // So here to record the 3rd party IME to be activated, and activate it
    397   // when SetEnabledExtensionImes happens later.
    398   if (MethodAwaitsExtensionLoad(input_method_id))
    399     pending_input_method_id = input_method_id;
    400 
    401   // Always lookup input method, even if it is the same as
    402   // |current_input_method| because If it is no longer in
    403   // |active_input_method_ids|, pick the first one in
    404   // |active_input_method_ids|.
    405   const InputMethodDescriptor* descriptor =
    406       manager_->LookupInputMethod(input_method_id, this);
    407   if (descriptor->id() != current_input_method.id()) {
    408     previous_input_method = current_input_method;
    409     current_input_method = *descriptor;
    410     notify_menu = true;
    411   }
    412 
    413   // Always change input method even if it is the same.
    414   // TODO(komatsu): Revisit if this is neccessary.
    415   if (IsActive())
    416     manager_->ChangeInputMethodInternal(*descriptor, show_message, notify_menu);
    417   manager_->RecordInputMethodUsage(current_input_method.id());
    418 }
    419 
    420 bool InputMethodManagerImpl::StateImpl::MethodAwaitsExtensionLoad(
    421     const std::string& input_method_id) const {
    422   // For 3rd party IME, when the user just logged in, SetEnabledExtensionImes
    423   // happens after activating the 3rd party IME.
    424   // So here to record the 3rd party IME to be activated, and activate it
    425   // when SetEnabledExtensionImes happens later.
    426   return !InputMethodIsActivated(input_method_id) &&
    427          extension_ime_util::IsExtensionIME(input_method_id);
    428 }
    429 
    430 void InputMethodManagerImpl::StateImpl::AddInputMethodExtension(
    431     const std::string& extension_id,
    432     const InputMethodDescriptors& descriptors,
    433     InputMethodEngineInterface* engine) {
    434   if (manager_->ui_session_ == STATE_TERMINATING)
    435     return;
    436 
    437   DCHECK(engine);
    438 
    439   manager_->engine_map_[extension_id] = engine;
    440 
    441   bool contain = false;
    442   for (size_t i = 0; i < descriptors.size(); i++) {
    443     const InputMethodDescriptor& descriptor = descriptors[i];
    444     const std::string& id = descriptor.id();
    445     extra_input_methods[id] = descriptor;
    446     if (Contains(enabled_extension_imes, id)) {
    447       if (!Contains(active_input_method_ids, id)) {
    448         active_input_method_ids.push_back(id);
    449       } else {
    450         DVLOG(1) << "AddInputMethodExtension: already added: " << id << ", "
    451                  << descriptor.name();
    452       }
    453       contain = true;
    454     }
    455   }
    456 
    457   if (IsActive()) {
    458     if (extension_id == extension_ime_util::GetExtensionIDFromInputMethodID(
    459                             current_input_method.id())) {
    460       IMEBridge::Get()->SetCurrentEngineHandler(engine);
    461       engine->Enable(extension_ime_util::GetComponentIDByInputMethodID(
    462           current_input_method.id()));
    463     }
    464 
    465     // Ensure that the input method daemon is running.
    466     if (contain)
    467       manager_->MaybeInitializeCandidateWindowController();
    468   }
    469 }
    470 
    471 void InputMethodManagerImpl::StateImpl::RemoveInputMethodExtension(
    472     const std::string& extension_id) {
    473   // Remove the active input methods with |extension_id|.
    474   std::vector<std::string> new_active_input_method_ids;
    475   for (size_t i = 0; i < active_input_method_ids.size(); ++i) {
    476     if (extension_id != extension_ime_util::GetExtensionIDFromInputMethodID(
    477                             active_input_method_ids[i]))
    478       new_active_input_method_ids.push_back(active_input_method_ids[i]);
    479   }
    480   active_input_method_ids.swap(new_active_input_method_ids);
    481 
    482   // Remove the extra input methods with |extension_id|.
    483   std::map<std::string, InputMethodDescriptor> new_extra_input_methods;
    484   for (std::map<std::string, InputMethodDescriptor>::iterator i =
    485            extra_input_methods.begin();
    486        i != extra_input_methods.end();
    487        ++i) {
    488     if (extension_id !=
    489         extension_ime_util::GetExtensionIDFromInputMethodID(i->first))
    490       new_extra_input_methods[i->first] = i->second;
    491   }
    492   extra_input_methods.swap(new_extra_input_methods);
    493 
    494   if (IsActive()) {
    495     if (IMEBridge::Get()->GetCurrentEngineHandler() ==
    496         manager_->engine_map_[extension_id]) {
    497       IMEBridge::Get()->SetCurrentEngineHandler(NULL);
    498     }
    499     manager_->engine_map_.erase(extension_id);
    500   }
    501 
    502   // If |current_input_method| is no longer in |active_input_method_ids|,
    503   // switch to the first one in |active_input_method_ids|.
    504   ChangeInputMethod(current_input_method.id(), false);
    505 }
    506 
    507 void InputMethodManagerImpl::StateImpl::GetInputMethodExtensions(
    508     InputMethodDescriptors* result) {
    509   // Build the extension input method descriptors from the extra input
    510   // methods cache |extra_input_methods|.
    511   std::map<std::string, InputMethodDescriptor>::iterator iter;
    512   for (iter = extra_input_methods.begin(); iter != extra_input_methods.end();
    513        ++iter) {
    514     if (extension_ime_util::IsExtensionIME(iter->first))
    515       result->push_back(iter->second);
    516   }
    517 }
    518 
    519 void InputMethodManagerImpl::StateImpl::SetEnabledExtensionImes(
    520     std::vector<std::string>* ids) {
    521   enabled_extension_imes.clear();
    522   enabled_extension_imes.insert(
    523       enabled_extension_imes.end(), ids->begin(), ids->end());
    524   bool active_imes_changed = false;
    525   bool switch_to_pending = false;
    526 
    527   for (std::map<std::string, InputMethodDescriptor>::iterator extra_iter =
    528            extra_input_methods.begin();
    529        extra_iter != extra_input_methods.end();
    530        ++extra_iter) {
    531     if (extension_ime_util::IsComponentExtensionIME(extra_iter->first))
    532       continue;  // Do not filter component extension.
    533 
    534     if (pending_input_method_id == extra_iter->first)
    535       switch_to_pending = true;
    536 
    537     std::vector<std::string>::iterator active_iter =
    538         std::find(active_input_method_ids.begin(),
    539                   active_input_method_ids.end(),
    540                   extra_iter->first);
    541 
    542     bool active = active_iter != active_input_method_ids.end();
    543     bool enabled = Contains(enabled_extension_imes, extra_iter->first);
    544 
    545     if (active && !enabled)
    546       active_input_method_ids.erase(active_iter);
    547 
    548     if (!active && enabled)
    549       active_input_method_ids.push_back(extra_iter->first);
    550 
    551     if (active == !enabled)
    552       active_imes_changed = true;
    553   }
    554 
    555   if (IsActive() && active_imes_changed) {
    556     manager_->MaybeInitializeCandidateWindowController();
    557 
    558     if (switch_to_pending) {
    559       ChangeInputMethod(pending_input_method_id, false);
    560       pending_input_method_id.clear();
    561     } else {
    562       // If |current_input_method| is no longer in |active_input_method_ids_|,
    563       // switch to the first one in |active_input_method_ids_|.
    564       ChangeInputMethod(current_input_method.id(), false);
    565     }
    566   }
    567 }
    568 
    569 void InputMethodManagerImpl::StateImpl::SetInputMethodLoginDefaultFromVPD(
    570     const std::string& locale,
    571     const std::string& oem_layout) {
    572   std::string layout;
    573   if (!oem_layout.empty()) {
    574     // If the OEM layout information is provided, use it.
    575     layout = oem_layout;
    576   } else {
    577     // Otherwise, determine the hardware keyboard from the locale.
    578     std::vector<std::string> input_method_ids;
    579     if (manager_->util_.GetInputMethodIdsFromLanguageCode(
    580             locale,
    581             chromeos::input_method::kKeyboardLayoutsOnly,
    582             &input_method_ids)) {
    583       // The output list |input_method_ids| is sorted by popularity, hence
    584       // input_method_ids[0] now contains the most popular keyboard layout
    585       // for the given locale.
    586       DCHECK_GE(input_method_ids.size(), 1U);
    587       layout = input_method_ids[0];
    588     }
    589   }
    590 
    591   if (layout.empty())
    592     return;
    593 
    594   std::vector<std::string> layouts;
    595   base::SplitString(layout, ',', &layouts);
    596   manager_->MigrateInputMethods(&layouts);
    597 
    598   PrefService* prefs = g_browser_process->local_state();
    599   prefs->SetString(prefs::kHardwareKeyboardLayout, JoinString(layouts, ","));
    600 
    601   // This asks the file thread to save the prefs (i.e. doesn't block).
    602   // The latest values of Local State reside in memory so we can safely
    603   // get the value of kHardwareKeyboardLayout even if the data is not
    604   // yet saved to disk.
    605   prefs->CommitPendingWrite();
    606 
    607   manager_->util_.UpdateHardwareLayoutCache();
    608 
    609   EnableLoginLayouts(locale, layouts);
    610   manager_->LoadNecessaryComponentExtensions(this);
    611 }
    612 
    613 void InputMethodManagerImpl::StateImpl::SetInputMethodLoginDefault() {
    614   // Set up keyboards. For example, when |locale| is "en-US", enable US qwerty
    615   // and US dvorak keyboard layouts.
    616   if (g_browser_process && g_browser_process->local_state()) {
    617     const std::string locale = g_browser_process->GetApplicationLocale();
    618     // If the preferred keyboard for the login screen has been saved, use it.
    619     PrefService* prefs = g_browser_process->local_state();
    620     std::string initial_input_method_id =
    621         prefs->GetString(chromeos::language_prefs::kPreferredKeyboardLayout);
    622     std::vector<std::string> input_methods_to_be_enabled;
    623     if (initial_input_method_id.empty()) {
    624       // If kPreferredKeyboardLayout is not specified, use the hardware layout.
    625       input_methods_to_be_enabled =
    626           manager_->util_.GetHardwareLoginInputMethodIds();
    627     } else {
    628       input_methods_to_be_enabled.push_back(initial_input_method_id);
    629     }
    630     EnableLoginLayouts(locale, input_methods_to_be_enabled);
    631     manager_->LoadNecessaryComponentExtensions(this);
    632   }
    633 }
    634 
    635 bool InputMethodManagerImpl::StateImpl::SwitchToNextInputMethod() {
    636   // Sanity checks.
    637   if (active_input_method_ids.empty()) {
    638     DVLOG(1) << "active input method is empty";
    639     return false;
    640   }
    641 
    642   if (current_input_method.id().empty()) {
    643     DVLOG(1) << "current_input_method is unknown";
    644     return false;
    645   }
    646 
    647   // Do not consume key event if there is only one input method is enabled.
    648   // Ctrl+Space or Alt+Shift may be used by other application.
    649   if (active_input_method_ids.size() == 1)
    650     return false;
    651 
    652   // Find the next input method and switch to it.
    653   SwitchToNextInputMethodInternal(active_input_method_ids,
    654                                   current_input_method.id());
    655   return true;
    656 }
    657 
    658 bool InputMethodManagerImpl::StateImpl::SwitchToPreviousInputMethod(
    659     const ui::Accelerator& accelerator) {
    660   // Sanity check.
    661   if (active_input_method_ids.empty()) {
    662     DVLOG(1) << "active input method is empty";
    663     return false;
    664   }
    665 
    666   // Do not consume key event if there is only one input method is enabled.
    667   // Ctrl+Space or Alt+Shift may be used by other application.
    668   if (active_input_method_ids.size() == 1)
    669     return false;
    670 
    671   if (accelerator.type() == ui::ET_KEY_RELEASED)
    672     return true;
    673 
    674   if (previous_input_method.id().empty() ||
    675       previous_input_method.id() == current_input_method.id()) {
    676     return SwitchToNextInputMethod();
    677   }
    678 
    679   std::vector<std::string>::const_iterator iter =
    680       std::find(active_input_method_ids.begin(),
    681                 active_input_method_ids.end(),
    682                 previous_input_method.id());
    683   if (iter == active_input_method_ids.end()) {
    684     // previous_input_method is not supported.
    685     return SwitchToNextInputMethod();
    686   }
    687   ChangeInputMethod(*iter, true);
    688 
    689   return true;
    690 }
    691 
    692 bool InputMethodManagerImpl::StateImpl::SwitchInputMethod(
    693     const ui::Accelerator& accelerator) {
    694   // Sanity check.
    695   if (active_input_method_ids.empty()) {
    696     DVLOG(1) << "active input method is empty";
    697     return false;
    698   }
    699 
    700   // Get the list of input method ids for the |accelerator|. For example, get
    701   // { "mozc-hangul", "xkb:kr:kr104:kor" } for ui::VKEY_DBE_SBCSCHAR.
    702   std::vector<std::string> input_method_ids_to_switch;
    703   switch (accelerator.key_code()) {
    704     case ui::VKEY_CONVERT:  // Henkan key on JP106 keyboard
    705       input_method_ids_to_switch.push_back(
    706           extension_ime_util::GetInputMethodIDByEngineID("nacl_mozc_jp"));
    707       break;
    708     case ui::VKEY_NONCONVERT:  // Muhenkan key on JP106 keyboard
    709       input_method_ids_to_switch.push_back(
    710           extension_ime_util::GetInputMethodIDByEngineID("xkb:jp::jpn"));
    711       break;
    712     case ui::VKEY_DBE_SBCSCHAR:  // ZenkakuHankaku key on JP106 keyboard
    713     case ui::VKEY_DBE_DBCSCHAR:
    714       input_method_ids_to_switch.push_back(
    715           extension_ime_util::GetInputMethodIDByEngineID("nacl_mozc_jp"));
    716       input_method_ids_to_switch.push_back(
    717           extension_ime_util::GetInputMethodIDByEngineID("xkb:jp::jpn"));
    718       break;
    719     default:
    720       NOTREACHED();
    721       break;
    722   }
    723   if (input_method_ids_to_switch.empty()) {
    724     DVLOG(1) << "Unexpected VKEY: " << accelerator.key_code();
    725     return false;
    726   }
    727 
    728   // Obtain the intersection of input_method_ids_to_switch and
    729   // active_input_method_ids. The order of IDs in active_input_method_ids is
    730   // preserved.
    731   std::vector<std::string> ids;
    732   for (size_t i = 0; i < input_method_ids_to_switch.size(); ++i) {
    733     const std::string& id = input_method_ids_to_switch[i];
    734     if (Contains(active_input_method_ids, id))
    735       ids.push_back(id);
    736   }
    737   if (ids.empty()) {
    738     // No input method for the accelerator is active. For example, we should
    739     // just ignore VKEY_HANGUL when mozc-hangul is not active.
    740     return false;
    741   }
    742 
    743   SwitchToNextInputMethodInternal(ids, current_input_method.id());
    744   return true;  // consume the accelerator.
    745 }
    746 
    747 void InputMethodManagerImpl::StateImpl::SwitchToNextInputMethodInternal(
    748     const std::vector<std::string>& input_method_ids,
    749     const std::string& current_input_methodid) {
    750   std::vector<std::string>::const_iterator iter = std::find(
    751       input_method_ids.begin(), input_method_ids.end(), current_input_methodid);
    752   if (iter != input_method_ids.end())
    753     ++iter;
    754   if (iter == input_method_ids.end())
    755     iter = input_method_ids.begin();
    756   ChangeInputMethod(*iter, true);
    757 }
    758 
    759 InputMethodDescriptor InputMethodManagerImpl::StateImpl::GetCurrentInputMethod()
    760     const {
    761   if (current_input_method.id().empty())
    762     return InputMethodUtil::GetFallbackInputMethodDescriptor();
    763 
    764   return current_input_method;
    765 }
    766 
    767 bool InputMethodManagerImpl::StateImpl::InputMethodIsActivated(
    768     const std::string& input_method_id) const {
    769   return Contains(active_input_method_ids, input_method_id);
    770 }
    771 
    772 // ------------------------ InputMethodManagerImpl
    773 bool InputMethodManagerImpl::IsLoginKeyboard(
    774     const std::string& layout) const {
    775   return util_.IsLoginKeyboard(layout);
    776 }
    777 
    778 bool InputMethodManagerImpl::MigrateInputMethods(
    779     std::vector<std::string>* input_method_ids) {
    780   return util_.MigrateInputMethods(input_method_ids);
    781 }
    782 
    783 // Starts or stops the system input method framework as needed.
    784 void InputMethodManagerImpl::ReconfigureIMFramework(
    785     InputMethodManagerImpl::StateImpl* state) {
    786   LoadNecessaryComponentExtensions(state);
    787 
    788   // Initialize candidate window controller and widgets such as
    789   // candidate window, infolist and mode indicator.  Note, mode
    790   // indicator is used by only keyboard layout input methods.
    791   if (state_.get() == state)
    792     MaybeInitializeCandidateWindowController();
    793 }
    794 
    795 void InputMethodManagerImpl::SetState(
    796     scoped_refptr<InputMethodManager::State> state) {
    797   DCHECK(state.get());
    798   InputMethodManagerImpl::StateImpl* new_impl_state =
    799       static_cast<InputMethodManagerImpl::StateImpl*>(state.get());
    800   const bool need_update_current_input_method =
    801       (state_.get()
    802            ? state_->current_input_method.id() !=
    803                  new_impl_state->current_input_method.id()
    804            : true);
    805   state_ = new_impl_state;
    806 
    807   if (state_.get() && state_->active_input_method_ids.size()) {
    808     // Initialize candidate window controller and widgets such as
    809     // candidate window, infolist and mode indicator.  Note, mode
    810     // indicator is used by only keyboard layout input methods.
    811     MaybeInitializeCandidateWindowController();
    812 
    813     if (need_update_current_input_method) {
    814       ChangeInputMethodInternal(state_->current_input_method,
    815                                 false /* show_message */,
    816                                 true /* notify_menu */);
    817     } else {
    818       // Update input method indicators (e.g. "US", "DV") in Chrome windows.
    819       FOR_EACH_OBSERVER(InputMethodManager::Observer,
    820                         observers_,
    821                         InputMethodChanged(this, false /* show_message */));
    822     }
    823   }
    824 }
    825 
    826 scoped_refptr<InputMethodManager::State>
    827 InputMethodManagerImpl::GetActiveIMEState() {
    828   return scoped_refptr<InputMethodManager::State>(state_.get());
    829 }
    830 
    831 InputMethodManagerImpl::InputMethodManagerImpl(
    832     scoped_ptr<InputMethodDelegate> delegate,
    833     bool enable_extension_loading)
    834     : delegate_(delegate.Pass()),
    835       ui_session_(STATE_LOGIN_SCREEN),
    836       state_(NULL),
    837       util_(delegate_.get()),
    838       component_extension_ime_manager_(new ComponentExtensionIMEManager()),
    839       enable_extension_loading_(enable_extension_loading) {
    840   if (base::SysInfo::IsRunningOnChromeOS())
    841     keyboard_.reset(ImeKeyboard::Create());
    842   else
    843     keyboard_.reset(new FakeImeKeyboard());
    844 
    845   // Initializes the system IME list.
    846   scoped_ptr<ComponentExtensionIMEManagerDelegate> comp_delegate(
    847       new ComponentExtensionIMEManagerImpl());
    848   component_extension_ime_manager_->Initialize(comp_delegate.Pass());
    849   const InputMethodDescriptors& descriptors =
    850       component_extension_ime_manager_->GetAllIMEAsInputMethodDescriptor();
    851   util_.ResetInputMethods(descriptors);
    852 
    853   // Initializes the stat id map.
    854   std::map<int, std::vector<std::string> > buckets;
    855   for (InputMethodDescriptors::const_iterator it = descriptors.begin();
    856        it != descriptors.end(); ++it) {
    857     char first_char;
    858     int cat_id = static_cast<int>(
    859         GetInputMethodCategory(it->id(), &first_char));
    860     int key = cat_id * 1000 + first_char;
    861     buckets[key].push_back(it->id());
    862   }
    863   for (std::map<int, std::vector<std::string>>::iterator i =
    864        buckets.begin(); i != buckets.end(); ++i) {
    865     std::sort(i->second.begin(), i->second.end());
    866     for (size_t j = 0; j < i->second.size() && j < 100; ++j) {
    867       int key = i->first * 100 + j;
    868       stat_id_map_[i->second[j]] = key;
    869     }
    870   }
    871 }
    872 
    873 InputMethodManagerImpl::~InputMethodManagerImpl() {
    874   if (candidate_window_controller_.get())
    875     candidate_window_controller_->RemoveObserver(this);
    876 }
    877 
    878 void InputMethodManagerImpl::RecordInputMethodUsage(
    879     std::string input_method_id) {
    880   UMA_HISTOGRAM_ENUMERATION("InputMethod.Category",
    881                             GetInputMethodCategory(input_method_id),
    882                             INPUT_METHOD_CATEGORY_MAX);
    883   UMA_HISTOGRAM_SPARSE_SLOWLY("InputMethod.ID",
    884                               stat_id_map_[input_method_id]);
    885 }
    886 
    887 void InputMethodManagerImpl::AddObserver(
    888     InputMethodManager::Observer* observer) {
    889   observers_.AddObserver(observer);
    890 }
    891 
    892 void InputMethodManagerImpl::AddCandidateWindowObserver(
    893     InputMethodManager::CandidateWindowObserver* observer) {
    894   candidate_window_observers_.AddObserver(observer);
    895 }
    896 
    897 void InputMethodManagerImpl::RemoveObserver(
    898     InputMethodManager::Observer* observer) {
    899   observers_.RemoveObserver(observer);
    900 }
    901 
    902 void InputMethodManagerImpl::RemoveCandidateWindowObserver(
    903     InputMethodManager::CandidateWindowObserver* observer) {
    904   candidate_window_observers_.RemoveObserver(observer);
    905 }
    906 
    907 InputMethodManager::UISessionState InputMethodManagerImpl::GetUISessionState() {
    908   return ui_session_;
    909 }
    910 
    911 void InputMethodManagerImpl::SetUISessionState(UISessionState new_ui_session) {
    912   ui_session_ = new_ui_session;
    913   switch (ui_session_) {
    914     case STATE_LOGIN_SCREEN:
    915       break;
    916     case STATE_BROWSER_SCREEN:
    917       break;
    918     case STATE_LOCK_SCREEN:
    919       break;
    920     case STATE_TERMINATING: {
    921       if (candidate_window_controller_.get())
    922         candidate_window_controller_.reset();
    923       break;
    924     }
    925   }
    926 }
    927 
    928 scoped_ptr<InputMethodDescriptors>
    929 InputMethodManagerImpl::GetSupportedInputMethods() const {
    930   return scoped_ptr<InputMethodDescriptors>(new InputMethodDescriptors).Pass();
    931 }
    932 
    933 const InputMethodDescriptor* InputMethodManagerImpl::LookupInputMethod(
    934     const std::string& input_method_id,
    935     InputMethodManagerImpl::StateImpl* state) {
    936   DCHECK(state);
    937 
    938   std::string input_method_id_to_switch = input_method_id;
    939 
    940   // Sanity check
    941   if (!state->InputMethodIsActivated(input_method_id)) {
    942     scoped_ptr<InputMethodDescriptors> input_methods(
    943         state->GetActiveInputMethods());
    944     DCHECK(!input_methods->empty());
    945     input_method_id_to_switch = input_methods->at(0).id();
    946     if (!input_method_id.empty()) {
    947       DVLOG(1) << "Can't change the current input method to "
    948                << input_method_id << " since the engine is not enabled. "
    949                << "Switch to " << input_method_id_to_switch << " instead.";
    950     }
    951   }
    952 
    953   const InputMethodDescriptor* descriptor = NULL;
    954   if (extension_ime_util::IsExtensionIME(input_method_id_to_switch)) {
    955     DCHECK(state->extra_input_methods.find(input_method_id_to_switch) !=
    956            state->extra_input_methods.end());
    957     descriptor = &(state->extra_input_methods[input_method_id_to_switch]);
    958   } else {
    959     descriptor =
    960         util_.GetInputMethodDescriptorFromId(input_method_id_to_switch);
    961     if (!descriptor)
    962       LOG(ERROR) << "Unknown input method id: " << input_method_id_to_switch;
    963   }
    964   DCHECK(descriptor);
    965   return descriptor;
    966 }
    967 
    968 void InputMethodManagerImpl::ChangeInputMethodInternal(
    969     const InputMethodDescriptor& descriptor,
    970     bool show_message,
    971     bool notify_menu) {
    972   // No need to switch input method when terminating.
    973   if (ui_session_ == STATE_TERMINATING)
    974     return;
    975 
    976   if (candidate_window_controller_.get())
    977     candidate_window_controller_->Hide();
    978 
    979   if (notify_menu) {
    980     // Clear property list.  Property list would be updated by
    981     // extension IMEs via InputMethodEngine::(Set|Update)MenuItems.
    982     // If the current input method is a keyboard layout, empty
    983     // properties are sufficient.
    984     const ash::ime::InputMethodMenuItemList empty_menu_item_list;
    985     ash::ime::InputMethodMenuManager* input_method_menu_manager =
    986         ash::ime::InputMethodMenuManager::GetInstance();
    987     input_method_menu_manager->SetCurrentInputMethodMenuItemList(
    988             empty_menu_item_list);
    989   }
    990 
    991   // Disable the current engine handler.
    992   IMEEngineHandlerInterface* engine =
    993       IMEBridge::Get()->GetCurrentEngineHandler();
    994   if (engine)
    995     engine->Disable();
    996 
    997   // Configure the next engine handler.
    998   // This must be after |current_input_method| has been set to new input
    999   // method, because engine's Enable() method needs to access it.
   1000   const std::string& extension_id =
   1001       extension_ime_util::GetExtensionIDFromInputMethodID(descriptor.id());
   1002   const std::string& component_id =
   1003       extension_ime_util::GetComponentIDByInputMethodID(descriptor.id());
   1004   engine = engine_map_[extension_id];
   1005 
   1006   IMEBridge::Get()->SetCurrentEngineHandler(engine);
   1007 
   1008   if (engine) {
   1009     engine->Enable(component_id);
   1010   } else {
   1011     // If no engine to enable, cancel the virtual keyboard url override so that
   1012     // it can use the fallback system virtual keyboard UI.
   1013     keyboard::SetOverrideContentUrl(GURL());
   1014     keyboard::KeyboardController* keyboard_controller =
   1015         keyboard::KeyboardController::GetInstance();
   1016     if (keyboard_controller)
   1017       keyboard_controller->Reload();
   1018   }
   1019 
   1020   // Change the keyboard layout to a preferred layout for the input method.
   1021   if (!keyboard_->SetCurrentKeyboardLayoutByName(
   1022           descriptor.GetPreferredKeyboardLayout())) {
   1023     LOG(ERROR) << "Failed to change keyboard layout to "
   1024                << descriptor.GetPreferredKeyboardLayout();
   1025   }
   1026 
   1027   // Update input method indicators (e.g. "US", "DV") in Chrome windows.
   1028   FOR_EACH_OBSERVER(InputMethodManager::Observer,
   1029                     observers_,
   1030                     InputMethodChanged(this, show_message));
   1031 }
   1032 
   1033 void InputMethodManagerImpl::LoadNecessaryComponentExtensions(
   1034     InputMethodManagerImpl::StateImpl* state) {
   1035   // Load component extensions but also update |active_input_method_ids| as
   1036   // some component extension IMEs may have been removed from the Chrome OS
   1037   // image. If specified component extension IME no longer exists, falling back
   1038   // to an existing IME.
   1039   DCHECK(state);
   1040   std::vector<std::string> unfiltered_input_method_ids;
   1041   unfiltered_input_method_ids.swap(state->active_input_method_ids);
   1042   for (size_t i = 0; i < unfiltered_input_method_ids.size(); ++i) {
   1043     if (!extension_ime_util::IsComponentExtensionIME(
   1044         unfiltered_input_method_ids[i])) {
   1045       // Legacy IMEs or xkb layouts are alwayes active.
   1046       state->active_input_method_ids.push_back(unfiltered_input_method_ids[i]);
   1047     } else if (component_extension_ime_manager_->IsWhitelisted(
   1048         unfiltered_input_method_ids[i])) {
   1049       if (enable_extension_loading_) {
   1050         component_extension_ime_manager_->LoadComponentExtensionIME(
   1051             state->profile, unfiltered_input_method_ids[i]);
   1052       }
   1053 
   1054       state->active_input_method_ids.push_back(unfiltered_input_method_ids[i]);
   1055     }
   1056   }
   1057 }
   1058 
   1059 void InputMethodManagerImpl::ActivateInputMethodMenuItem(
   1060     const std::string& key) {
   1061   DCHECK(!key.empty());
   1062 
   1063   if (ash::ime::InputMethodMenuManager::GetInstance()->
   1064       HasInputMethodMenuItemForKey(key)) {
   1065     IMEEngineHandlerInterface* engine =
   1066         IMEBridge::Get()->GetCurrentEngineHandler();
   1067     if (engine)
   1068       engine->PropertyActivate(key);
   1069     return;
   1070   }
   1071 
   1072   DVLOG(1) << "ActivateInputMethodMenuItem: unknown key: " << key;
   1073 }
   1074 
   1075 bool InputMethodManagerImpl::IsISOLevel5ShiftUsedByCurrentInputMethod() const {
   1076   return keyboard_->IsISOLevel5ShiftAvailable();
   1077 }
   1078 
   1079 bool InputMethodManagerImpl::IsAltGrUsedByCurrentInputMethod() const {
   1080   return keyboard_->IsAltGrAvailable();
   1081 }
   1082 
   1083 ImeKeyboard* InputMethodManagerImpl::GetImeKeyboard() {
   1084   return keyboard_.get();
   1085 }
   1086 
   1087 InputMethodUtil* InputMethodManagerImpl::GetInputMethodUtil() {
   1088   return &util_;
   1089 }
   1090 
   1091 ComponentExtensionIMEManager*
   1092     InputMethodManagerImpl::GetComponentExtensionIMEManager() {
   1093   return component_extension_ime_manager_.get();
   1094 }
   1095 
   1096 scoped_refptr<InputMethodManager::State> InputMethodManagerImpl::CreateNewState(
   1097     Profile* profile) {
   1098   return scoped_refptr<InputMethodManager::State>(new StateImpl(this, profile));
   1099 }
   1100 
   1101 void InputMethodManagerImpl::SetCandidateWindowControllerForTesting(
   1102     CandidateWindowController* candidate_window_controller) {
   1103   candidate_window_controller_.reset(candidate_window_controller);
   1104   candidate_window_controller_->AddObserver(this);
   1105 }
   1106 
   1107 void InputMethodManagerImpl::SetImeKeyboardForTesting(ImeKeyboard* keyboard) {
   1108   keyboard_.reset(keyboard);
   1109 }
   1110 
   1111 void InputMethodManagerImpl::InitializeComponentExtensionForTesting(
   1112     scoped_ptr<ComponentExtensionIMEManagerDelegate> delegate) {
   1113   component_extension_ime_manager_->Initialize(delegate.Pass());
   1114   util_.ResetInputMethods(
   1115       component_extension_ime_manager_->GetAllIMEAsInputMethodDescriptor());
   1116 }
   1117 
   1118 void InputMethodManagerImpl::CandidateClicked(int index) {
   1119   IMEEngineHandlerInterface* engine =
   1120       IMEBridge::Get()->GetCurrentEngineHandler();
   1121   if (engine)
   1122     engine->CandidateClicked(index);
   1123 }
   1124 
   1125 void InputMethodManagerImpl::CandidateWindowOpened() {
   1126   FOR_EACH_OBSERVER(InputMethodManager::CandidateWindowObserver,
   1127                     candidate_window_observers_,
   1128                     CandidateWindowOpened(this));
   1129 }
   1130 
   1131 void InputMethodManagerImpl::CandidateWindowClosed() {
   1132   FOR_EACH_OBSERVER(InputMethodManager::CandidateWindowObserver,
   1133                     candidate_window_observers_,
   1134                     CandidateWindowClosed(this));
   1135 }
   1136 
   1137 void InputMethodManagerImpl::MaybeInitializeCandidateWindowController() {
   1138   if (candidate_window_controller_.get())
   1139     return;
   1140 
   1141   candidate_window_controller_.reset(
   1142       CandidateWindowController::CreateCandidateWindowController());
   1143   candidate_window_controller_->AddObserver(this);
   1144 }
   1145 
   1146 }  // namespace input_method
   1147 }  // namespace chromeos
   1148