Upstream version 9.38.198.0
[platform/framework/web/crosswalk.git] / src / chrome / browser / chromeos / input_method / input_method_manager_impl.cc
index 8e3a62b..87518b9 100644 (file)
@@ -22,7 +22,6 @@
 #include "chrome/browser/chromeos/input_method/component_extension_ime_manager_impl.h"
 #include "chrome/browser/chromeos/input_method/input_method_engine.h"
 #include "chrome/browser/chromeos/language_preferences.h"
-#include "chrome/browser/chromeos/login/users/user_manager.h"
 #include "chrome/browser/profiles/profile_manager.h"
 #include "chrome/common/pref_names.h"
 #include "chromeos/ime/component_extension_ime_manager.h"
@@ -57,12 +56,23 @@ bool InputMethodManagerImpl::MigrateInputMethods(
 }
 
 InputMethodManagerImpl::InputMethodManagerImpl(
-    scoped_ptr<InputMethodDelegate> delegate)
+    scoped_ptr<InputMethodDelegate> delegate, bool enable_extension_loading)
     : delegate_(delegate.Pass()),
       state_(STATE_LOGIN_SCREEN),
-      util_(delegate_.get(), whitelist_.GetSupportedInputMethods()),
+      util_(delegate_.get()),
       component_extension_ime_manager_(new ComponentExtensionIMEManager()),
-      weak_ptr_factory_(this) {
+      enable_extension_loading_(enable_extension_loading) {
+  if (base::SysInfo::IsRunningOnChromeOS())
+    keyboard_.reset(ImeKeyboard::Create());
+  else
+    keyboard_.reset(new FakeImeKeyboard());
+
+  // Initializes the system IME list.
+  scoped_ptr<ComponentExtensionIMEManagerDelegate> comp_delegate(
+      new ComponentExtensionIMEManagerImpl());
+  component_extension_ime_manager_->Initialize(comp_delegate.Pass());
+  util_.ResetInputMethods(
+      component_extension_ime_manager_->GetAllIMEAsInputMethodDescriptor());
 }
 
 InputMethodManagerImpl::~InputMethodManagerImpl() {
@@ -90,6 +100,10 @@ void InputMethodManagerImpl::RemoveCandidateWindowObserver(
   candidate_window_observers_.RemoveObserver(observer);
 }
 
+InputMethodManager::State InputMethodManagerImpl::GetState() {
+  return state_;
+}
+
 void InputMethodManagerImpl::SetState(State new_state) {
   const State old_state = state_;
   state_ = new_state;
@@ -113,8 +127,6 @@ void InputMethodManagerImpl::SetState(State new_state) {
 
 scoped_ptr<InputMethodDescriptors>
 InputMethodManagerImpl::GetSupportedInputMethods() const {
-  if (!IsXkbComponentExtensionAvailable())
-    return whitelist_.GetSupportedInputMethods().Pass();
   return scoped_ptr<InputMethodDescriptors>(new InputMethodDescriptors).Pass();
 }
 
@@ -315,6 +327,13 @@ bool InputMethodManagerImpl::ChangeInputMethodInternal(
 
   // Sanity check.
   if (!InputMethodIsActivated(input_method_id)) {
+    // For 3rd party IME, when the user just logged in, SetEnabledExtensionImes
+    // happens after activating the 3rd party IME.
+    // So here to record the 3rd party IME to be activated, and activate it
+    // when SetEnabledExtensionImes happens later.
+    if (extension_ime_util::IsExtensionIME(input_method_id))
+      pending_input_method_id_ = input_method_id;
+
     scoped_ptr<InputMethodDescriptors> input_methods(GetActiveInputMethods());
     DCHECK(!input_methods->empty());
     input_method_id_to_switch = input_methods->at(0).id();
@@ -325,41 +344,10 @@ bool InputMethodManagerImpl::ChangeInputMethodInternal(
     }
   }
 
-  if (!component_extension_ime_manager_->IsInitialized() &&
-      !InputMethodUtil::IsKeyboardLayout(input_method_id_to_switch)) {
-    // We can't change input method before the initialization of
-    // component extension ime manager.  ChangeInputMethod will be
-    // called with |pending_input_method_| when the initialization is
-    // done.
-    pending_input_method_ = input_method_id_to_switch;
-    return false;
-  }
-  pending_input_method_.clear();
-
   // Hide candidate window and info list.
   if (candidate_window_controller_.get())
     candidate_window_controller_->Hide();
 
-  // Disable the current engine handler.
-  IMEEngineHandlerInterface* engine =
-      IMEBridge::Get()->GetCurrentEngineHandler();
-  if (engine)
-    engine->Disable();
-
-  // Configure the next engine handler.
-  if (InputMethodUtil::IsKeyboardLayout(input_method_id_to_switch) &&
-      !extension_ime_util::IsKeyboardLayoutExtension(
-          input_method_id_to_switch)) {
-    IMEBridge::Get()->SetCurrentEngineHandler(NULL);
-  } else {
-    IMEEngineHandlerInterface* next_engine =
-        profile_engine_map_[GetProfile()][input_method_id_to_switch];
-    if (next_engine) {
-      IMEBridge::Get()->SetCurrentEngineHandler(next_engine);
-      next_engine->Enable();
-    }
-  }
-
   // TODO(komatsu): Check if it is necessary to perform the above routine
   // when the current input method is equal to |input_method_id_to_swich|.
   if (current_input_method_.id() != input_method_id_to_switch) {
@@ -390,6 +378,26 @@ bool InputMethodManagerImpl::ChangeInputMethodInternal(
     current_input_method_ = *descriptor;
   }
 
+  // Disable the current engine handler.
+  IMEEngineHandlerInterface* engine =
+      IMEBridge::Get()->GetCurrentEngineHandler();
+  if (engine)
+    engine->Disable();
+
+  // Configure the next engine handler.
+  // This must be after |current_input_method_| has been set to new input
+  // method, because engine's Enable() method needs to access it.
+  const std::string& extension_id =
+      extension_ime_util::GetExtensionIDFromInputMethodID(
+          input_method_id_to_switch);
+  const std::string& component_id =
+      extension_ime_util::GetComponentIDByInputMethodID(
+          input_method_id_to_switch);
+  engine = engine_map_[extension_id];
+  IMEBridge::Get()->SetCurrentEngineHandler(engine);
+  if (engine)
+    engine->Enable(component_id);
+
   // Change the keyboard layout to a preferred layout for the input method.
   if (!keyboard_->SetCurrentKeyboardLayoutByName(
           current_input_method_.GetPreferredKeyboardLayout())) {
@@ -404,41 +412,7 @@ bool InputMethodManagerImpl::ChangeInputMethodInternal(
   return true;
 }
 
-bool InputMethodManagerImpl::IsXkbComponentExtensionAvailable() const {
-  if (!component_extension_ime_manager_->IsInitialized())
-    return false;
-  InputMethodDescriptors imes =
-      component_extension_ime_manager_->GetAllIMEAsInputMethodDescriptor();
-  for (size_t i = 0; i < imes.size(); ++i) {
-    if (StartsWithASCII(extension_ime_util::MaybeGetLegacyXkbId(
-        imes[i].id()), "xkb:", true))
-      return true;
-  }
-  return false;
-}
-
-void InputMethodManagerImpl::OnComponentExtensionInitialized(
-    scoped_ptr<ComponentExtensionIMEManagerDelegate> delegate) {
-  DCHECK(thread_checker_.CalledOnValidThread());
-  component_extension_ime_manager_->Initialize(delegate.Pass());
-  InputMethodDescriptors imes =
-      component_extension_ime_manager_->GetAllIMEAsInputMethodDescriptor();
-  // In case of XKB extension is not available (e.g. linux_chromeos), don't
-  // reset the input methods in InputMethodUtil, Instead append input methods.
-  if (IsXkbComponentExtensionAvailable())
-    util_.ResetInputMethods(imes);
-  else
-    util_.AppendInputMethods(imes);
-
-  LoadNecessaryComponentExtensions();
-
-  if (!pending_input_method_.empty())
-    ChangeInputMethodInternal(pending_input_method_, false);
-}
-
 void InputMethodManagerImpl::LoadNecessaryComponentExtensions() {
-  if (!component_extension_ime_manager_->IsInitialized())
-    return;
   // Load component extensions but also update |active_input_method_ids_| as
   // some component extension IMEs may have been removed from the Chrome OS
   // image. If specified component extension IME no longer exists, falling back
@@ -452,13 +426,12 @@ void InputMethodManagerImpl::LoadNecessaryComponentExtensions() {
       active_input_method_ids_.push_back(unfiltered_input_method_ids[i]);
     } else if (component_extension_ime_manager_->IsWhitelisted(
         unfiltered_input_method_ids[i])) {
-      component_extension_ime_manager_->LoadComponentExtensionIME(
-          unfiltered_input_method_ids[i]);
+      if (enable_extension_loading_)
+        component_extension_ime_manager_->LoadComponentExtensionIME(
+            unfiltered_input_method_ids[i]);
       active_input_method_ids_.push_back(unfiltered_input_method_ids[i]);
     }
   }
-  // TODO(shuchen): move this call in ComponentExtensionIMEManager.
-  component_extension_ime_manager_->NotifyInitialized();
 }
 
 void InputMethodManagerImpl::ActivateInputMethodMenuItem(
@@ -478,58 +451,70 @@ void InputMethodManagerImpl::ActivateInputMethodMenuItem(
 }
 
 void InputMethodManagerImpl::AddInputMethodExtension(
-    Profile* profile,
-    const std::string& id,
+    const std::string& extension_id,
+    const InputMethodDescriptors& descriptors,
     InputMethodEngineInterface* engine) {
   if (state_ == STATE_TERMINATING)
     return;
 
   DCHECK(engine);
 
-  profile_engine_map_[profile][id] = engine;
+  engine_map_[extension_id] = engine;
 
-  if (id == current_input_method_.id()) {
+  if (extension_id == extension_ime_util::GetExtensionIDFromInputMethodID(
+                          current_input_method_.id())) {
     IMEBridge::Get()->SetCurrentEngineHandler(engine);
-    engine->Enable();
-  }
-
-  if (extension_ime_util::IsComponentExtensionIME(id))
-    return;
-
-  CHECK(extension_ime_util::IsExtensionIME(id))
-      << id << "is not a valid extension input method ID";
-
-  const InputMethodDescriptor& descriptor = engine->GetDescriptor();
-  extra_input_methods_[id] = descriptor;
-
-  if (Contains(enabled_extension_imes_, id)) {
-    if (!Contains(active_input_method_ids_, id)) {
-      active_input_method_ids_.push_back(id);
-    } else {
-      DVLOG(1) << "AddInputMethodExtension: alread added: "
-               << id << ", " << descriptor.name();
+    engine->Enable(extension_ime_util::GetComponentIDByInputMethodID(
+        current_input_method_.id()));
+  }
+
+  bool contain = false;
+  for (size_t i = 0; i < descriptors.size(); i++) {
+    const InputMethodDescriptor& descriptor = descriptors[i];
+    const std::string& id = descriptor.id();
+    extra_input_methods_[id] = descriptor;
+    if (Contains(enabled_extension_imes_, id)) {
+      if (!Contains(active_input_method_ids_, id)) {
+        active_input_method_ids_.push_back(id);
+      } else {
+        DVLOG(1) << "AddInputMethodExtension: already added: " << id << ", "
+                 << descriptor.name();
+      }
+      contain = true;
     }
+  }
 
-    // Ensure that the input method daemon is running.
+  // Ensure that the input method daemon is running.
+  if (contain)
     MaybeInitializeCandidateWindowController();
-  }
 }
 
-void InputMethodManagerImpl::RemoveInputMethodExtension(Profile* profile,
-                                                        const std::string& id) {
-  if (!extension_ime_util::IsExtensionIME(id))
-    DVLOG(1) << id << " is not a valid extension input method ID.";
+void InputMethodManagerImpl::RemoveInputMethodExtension(
+    const std::string& extension_id) {
+  // Remove the active input methods with |extension_id|.
+  std::vector<std::string> new_active_input_method_ids;
+  for (size_t i = 0; i < active_input_method_ids_.size(); ++i) {
+    if (extension_id != extension_ime_util::GetExtensionIDFromInputMethodID(
+                            active_input_method_ids_[i]))
+      new_active_input_method_ids.push_back(active_input_method_ids_[i]);
+  }
+  active_input_method_ids_.swap(new_active_input_method_ids);
 
-  std::vector<std::string>::iterator i = std::find(
-      active_input_method_ids_.begin(), active_input_method_ids_.end(), id);
-  if (i != active_input_method_ids_.end())
-    active_input_method_ids_.erase(i);
-  extra_input_methods_.erase(id);
+  // Remove the extra input methods with |extension_id|.
+  std::map<std::string, InputMethodDescriptor> new_extra_input_methods;
+  for (std::map<std::string, InputMethodDescriptor>::iterator i =
+           extra_input_methods_.begin();
+       i != extra_input_methods_.end();
+       ++i) {
+    if (extension_id !=
+        extension_ime_util::GetExtensionIDFromInputMethodID(i->first))
+      new_extra_input_methods[i->first] = i->second;
+  }
+  extra_input_methods_.swap(new_extra_input_methods);
 
-  EngineMap& engine_map = profile_engine_map_[profile];
-  if (IMEBridge::Get()->GetCurrentEngineHandler() == engine_map[id])
+  if (IMEBridge::Get()->GetCurrentEngineHandler() == engine_map_[extension_id])
     IMEBridge::Get()->SetCurrentEngineHandler(NULL);
-  engine_map.erase(id);
+  engine_map_.erase(extension_id);
 
   // No need to switch input method when terminating.
   if (state_ != STATE_TERMINATING) {
@@ -559,6 +544,7 @@ void InputMethodManagerImpl::SetEnabledExtensionImes(
                                  ids->end());
 
   bool active_imes_changed = false;
+  bool switch_to_pending = false;
 
   for (std::map<std::string, InputMethodDescriptor>::iterator extra_iter =
        extra_input_methods_.begin(); extra_iter != extra_input_methods_.end();
@@ -566,6 +552,10 @@ void InputMethodManagerImpl::SetEnabledExtensionImes(
     if (extension_ime_util::IsComponentExtensionIME(
         extra_iter->first))
       continue;  // Do not filter component extension.
+
+    if (pending_input_method_id_ == extra_iter->first)
+      switch_to_pending = true;
+
     std::vector<std::string>::iterator active_iter = std::find(
         active_input_method_ids_.begin(), active_input_method_ids_.end(),
         extra_iter->first);
@@ -586,9 +576,14 @@ void InputMethodManagerImpl::SetEnabledExtensionImes(
   if (active_imes_changed) {
     MaybeInitializeCandidateWindowController();
 
-    // If |current_input_method| is no longer in |active_input_method_ids_|,
-    // switch to the first one in |active_input_method_ids_|.
-    ChangeInputMethod(current_input_method_.id());
+    if (switch_to_pending) {
+      ChangeInputMethod(pending_input_method_id_);
+      pending_input_method_id_.clear();
+    } else {
+      // If |current_input_method| is no longer in |active_input_method_ids_|,
+      // switch to the first one in |active_input_method_ids_|.
+      ChangeInputMethod(current_input_method_.id());
+    }
   }
 }
 
@@ -632,6 +627,7 @@ void InputMethodManagerImpl::SetInputMethodLoginDefaultFromVPD(
   util_.UpdateHardwareLayoutCache();
 
   EnableLoginLayouts(locale, layouts);
+  LoadNecessaryComponentExtensions();
 }
 
 void InputMethodManagerImpl::SetInputMethodLoginDefault() {
@@ -651,6 +647,7 @@ void InputMethodManagerImpl::SetInputMethodLoginDefault() {
       input_methods_to_be_enabled.push_back(initial_input_method_id);
     }
     EnableLoginLayouts(locale, input_methods_to_be_enabled);
+    LoadNecessaryComponentExtensions();
   }
 }
 
@@ -804,36 +801,9 @@ InputMethodUtil* InputMethodManagerImpl::GetInputMethodUtil() {
 
 ComponentExtensionIMEManager*
     InputMethodManagerImpl::GetComponentExtensionIMEManager() {
-  DCHECK(thread_checker_.CalledOnValidThread());
   return component_extension_ime_manager_.get();
 }
 
-void InputMethodManagerImpl::InitializeComponentExtension() {
-  ComponentExtensionIMEManagerImpl* impl =
-      new ComponentExtensionIMEManagerImpl();
-  scoped_ptr<ComponentExtensionIMEManagerDelegate> delegate(impl);
-  impl->InitializeAsync(base::Bind(
-                       &InputMethodManagerImpl::OnComponentExtensionInitialized,
-                       weak_ptr_factory_.GetWeakPtr(),
-                       base::Passed(&delegate)));
-}
-
-void InputMethodManagerImpl::Init(base::SequencedTaskRunner* ui_task_runner) {
-  DCHECK(thread_checker_.CalledOnValidThread());
-
-  if (base::SysInfo::IsRunningOnChromeOS())
-    keyboard_.reset(ImeKeyboard::Create());
-  else
-    keyboard_.reset(new FakeImeKeyboard());
-
-  // We can't call impl->Initialize here, because file thread is not available
-  // at this moment.
-  ui_task_runner->PostTask(
-      FROM_HERE,
-      base::Bind(&InputMethodManagerImpl::InitializeComponentExtension,
-                 weak_ptr_factory_.GetWeakPtr()));
-}
-
 void InputMethodManagerImpl::SetCandidateWindowControllerForTesting(
     CandidateWindowController* candidate_window_controller) {
   candidate_window_controller_.reset(candidate_window_controller);
@@ -846,7 +816,9 @@ void InputMethodManagerImpl::SetImeKeyboardForTesting(ImeKeyboard* keyboard) {
 
 void InputMethodManagerImpl::InitializeComponentExtensionForTesting(
     scoped_ptr<ComponentExtensionIMEManagerDelegate> delegate) {
-  OnComponentExtensionInitialized(delegate.Pass());
+  component_extension_ime_manager_->Initialize(delegate.Pass());
+  util_.ResetInputMethods(
+      component_extension_ime_manager_->GetAllIMEAsInputMethodDescriptor());
 }
 
 void InputMethodManagerImpl::CandidateClicked(int index) {
@@ -925,9 +897,5 @@ void InputMethodManagerImpl::MaybeInitializeCandidateWindowController() {
   candidate_window_controller_->AddObserver(this);
 }
 
-Profile* InputMethodManagerImpl::GetProfile() const {
-  return ProfileManager::GetActiveUserProfile();
-}
-
 }  // namespace input_method
 }  // namespace chromeos