diff options
15 files changed, 493 insertions, 24 deletions
diff --git a/chrome/browser/chromeos/input_method/input_method_manager_impl.cc b/chrome/browser/chromeos/input_method/input_method_manager_impl.cc index fcb8919..c0082d0 100644 --- a/chrome/browser/chromeos/input_method/input_method_manager_impl.cc +++ b/chrome/browser/chromeos/input_method/input_method_manager_impl.cc @@ -110,6 +110,12 @@ const struct MigrationHangulKeyboardToInputMethodID { } // namespace +bool InputMethodManagerImpl::IsFullLatinKeyboard( + const std::string& layout) const { + const std::string& lang = util_.GetLanguageCodeFromInputMethodId(layout); + return full_latin_keyboard_checker.IsFullLatinKeyboard(layout, lang); +} + InputMethodManagerImpl::InputMethodManagerImpl( scoped_ptr<InputMethodDelegate> delegate) : delegate_(delegate.Pass()), @@ -207,6 +213,11 @@ InputMethodManagerImpl::GetActiveInputMethods() const { return result.Pass(); } +const std::vector<std::string>& +InputMethodManagerImpl::GetActiveInputMethodIds() const { + return active_input_method_ids_; +} + size_t InputMethodManagerImpl::GetNumActiveInputMethods() const { return active_input_method_ids_.size(); } @@ -250,6 +261,46 @@ void InputMethodManagerImpl::EnableLayouts(const std::string& language_code, ChangeInputMethod(initial_layout); // you can pass empty |initial_layout|. } +// Adds new input method to given list. +bool InputMethodManagerImpl::EnableInputMethodImpl( + const std::string& input_method_id, + std::vector<std::string>& new_active_input_method_ids) const { + if (!util_.IsValidInputMethodId(input_method_id)) { + DVLOG(1) << "EnableInputMethod: Invalid ID: " << input_method_id; + return false; + } + + if (!Contains(new_active_input_method_ids, input_method_id)) + new_active_input_method_ids.push_back(input_method_id); + + return true; +} + +// Starts or stops the system input method framework as needed. +void InputMethodManagerImpl::ReconfigureIMFramework() { + if (component_extension_ime_manager_->IsInitialized()) + LoadNecessaryComponentExtensions(); + + if (ContainsOnlyKeyboardLayout(active_input_method_ids_)) { + // Do NOT call ibus_controller_->Stop(); here to work around a crash issue + // at crbug.com/27051. + // TODO(yusukes): We can safely call Stop(); here once crbug.com/26443 + // is implemented. + } else { + MaybeInitializeCandidateWindowController(); + IBusDaemonController::GetInstance()->Start(); + } +} + +bool InputMethodManagerImpl::EnableInputMethod( + const std::string& input_method_id) { + if (!EnableInputMethodImpl(input_method_id, active_input_method_ids_)) + return false; + + ReconfigureIMFramework(); + return true; +} + bool InputMethodManagerImpl::EnableInputMethods( const std::vector<std::string>& new_active_input_method_ids) { if (state_ == STATE_TERMINATING) @@ -258,13 +309,9 @@ bool InputMethodManagerImpl::EnableInputMethods( // Filter unknown or obsolete IDs. std::vector<std::string> new_active_input_method_ids_filtered; - for (size_t i = 0; i < new_active_input_method_ids.size(); ++i) { - const std::string& input_method_id = new_active_input_method_ids[i]; - if (util_.IsValidInputMethodId(input_method_id)) - new_active_input_method_ids_filtered.push_back(input_method_id); - else - DVLOG(1) << "EnableInputMethods: Invalid ID: " << input_method_id; - } + for (size_t i = 0; i < new_active_input_method_ids.size(); ++i) + EnableInputMethodImpl(new_active_input_method_ids[i], + new_active_input_method_ids_filtered); if (new_active_input_method_ids_filtered.empty()) { DVLOG(1) << "EnableInputMethods: No valid input method ID"; @@ -280,18 +327,7 @@ bool InputMethodManagerImpl::EnableInputMethods( } active_input_method_ids_.swap(new_active_input_method_ids_filtered); - if (component_extension_ime_manager_->IsInitialized()) - LoadNecessaryComponentExtensions(); - - if (ContainOnlyKeyboardLayout(active_input_method_ids_)) { - // Do NOT call ibus_controller_->Stop(); here to work around a crash issue - // at crosbug.com/27051. - // TODO(yusukes): We can safely call Stop(); here once crosbug.com/26443 - // is implemented. - } else { - MaybeInitializeCandidateWindowController(); - IBusDaemonController::GetInstance()->Start(); - } + ReconfigureIMFramework(); // If |current_input_method| is no longer in |active_input_method_ids_|, // ChangeInputMethod() picks the first one in |active_input_method_ids_|. @@ -564,7 +600,7 @@ void InputMethodManagerImpl::RemoveInputMethodExtension(const std::string& id) { active_input_method_ids_.erase(i); extra_input_methods_.erase(id); - if (ContainOnlyKeyboardLayout(active_input_method_ids_)) { + if (ContainsOnlyKeyboardLayout(active_input_method_ids_)) { // Do NOT call ibus_controller_->Stop(); here to work around a crash issue // at crosbug.com/27051. // TODO(yusukes): We can safely call Stop(); here once crosbug.com/26443 @@ -918,7 +954,7 @@ bool InputMethodManagerImpl::InputMethodIsActivated( return Contains(active_input_method_ids_, input_method_id); } -bool InputMethodManagerImpl::ContainOnlyKeyboardLayout( +bool InputMethodManagerImpl::ContainsOnlyKeyboardLayout( const std::vector<std::string>& value) { for (size_t i = 0; i < value.size(); ++i) { if (!InputMethodUtil::IsKeyboardLayout(value[i])) diff --git a/chrome/browser/chromeos/input_method/input_method_manager_impl.h b/chrome/browser/chromeos/input_method/input_method_manager_impl.h index 521e04a..16de674 100644 --- a/chrome/browser/chromeos/input_method/input_method_manager_impl.h +++ b/chrome/browser/chromeos/input_method/input_method_manager_impl.h @@ -14,6 +14,7 @@ #include "base/threading/thread_checker.h" #include "chrome/browser/chromeos/input_method/candidate_window_controller.h" #include "chrome/browser/chromeos/input_method/ibus_controller.h" +#include "chrome/browser/chromeos/input_method/input_method_manager_impl_ll.h" #include "chrome/browser/chromeos/input_method/input_method_util.h" #include "chromeos/ime/ibus_daemon_controller.h" #include "chromeos/ime/input_method_manager.h" @@ -58,11 +59,15 @@ class InputMethodManagerImpl : public InputMethodManager, GetSupportedInputMethods() const OVERRIDE; virtual scoped_ptr<InputMethodDescriptors> GetActiveInputMethods() const OVERRIDE; + virtual const std::vector<std::string>& GetActiveInputMethodIds() const + OVERRIDE; virtual size_t GetNumActiveInputMethods() const OVERRIDE; virtual void EnableLayouts(const std::string& language_code, const std::string& initial_layout) OVERRIDE; virtual bool EnableInputMethods( const std::vector<std::string>& new_active_input_method_ids) OVERRIDE; + virtual bool EnableInputMethod(const std::string& new_active_input_method_id) + OVERRIDE; virtual bool MigrateOldInputMethods( std::vector<std::string>* input_method_ids) OVERRIDE; virtual bool MigrateKoreanKeyboard( @@ -95,6 +100,7 @@ class InputMethodManagerImpl : public InputMethodManager, virtual InputMethodUtil* GetInputMethodUtil() OVERRIDE; virtual ComponentExtensionIMEManager* GetComponentExtensionIMEManager() OVERRIDE; + virtual bool IsFullLatinKeyboard(const std::string& layout) const OVERRIDE; // Sets |ibus_controller_|. void SetIBusControllerForTesting(IBusController* ibus_controller); @@ -135,7 +141,7 @@ class InputMethodManagerImpl : public InputMethodManager, // Returns true if the given input method config value is a string list // that only contains an input method ID of a keyboard layout. - bool ContainOnlyKeyboardLayout(const std::vector<std::string>& value); + bool ContainsOnlyKeyboardLayout(const std::vector<std::string>& value); // Returns true if the connection to ibus-daemon is established. bool IsIBusConnectionAlive(); @@ -165,6 +171,15 @@ class InputMethodManagerImpl : public InputMethodManager, // TODO(nona): Support dynamical unloading. void LoadNecessaryComponentExtensions(); + // Adds new input method to given list if possible + bool EnableInputMethodImpl( + const std::string& input_method_id, + std::vector<std::string>& new_active_input_method_ids) const; + + // Starts or stops the system input method framework as needed. + // (after list of enabled input methods has been updated) + void ReconfigureIMFramework(); + scoped_ptr<InputMethodDelegate> delegate_; // The current browser status. @@ -223,6 +238,10 @@ class InputMethodManagerImpl : public InputMethodManager, base::WeakPtrFactory<InputMethodManagerImpl> weak_ptr_factory_; + // Check if input method id allows full latin input (for entering passwords on + // login screen) + FullLatinKeyboardLayoutChecker full_latin_keyboard_checker; + DISALLOW_COPY_AND_ASSIGN(InputMethodManagerImpl); }; diff --git a/chrome/browser/chromeos/input_method/input_method_manager_impl_ll.cc b/chrome/browser/chromeos/input_method/input_method_manager_impl_ll.cc new file mode 100644 index 0000000..7bf850c --- /dev/null +++ b/chrome/browser/chromeos/input_method/input_method_manager_impl_ll.cc @@ -0,0 +1,124 @@ +// Copyright 2013 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "chrome/browser/chromeos/input_method/input_method_manager_impl_ll.h" + +#include <string.h> + +#include <limits> + +namespace chromeos { +namespace input_method { + +struct KBDList { + const char* const* layouts; + size_t size; +}; + +namespace { + +// A language may have some special layout that allows full latin input. +static const char* const kJPFullLatinKeyboardLayouts[] = { + "xkb:jp::jpn" +}; + +static const KBDList kJPFullLatinKeyboards = { + kJPFullLatinKeyboardLayouts, arraysize(kJPFullLatinKeyboardLayouts) +}; + +// A list of languages and their layouts having full 26 latin letter set on +// keyboard. + +// If permitted_layouts is NULL, then all keyboard layouts for the +// language are "Full Latin Input" and can be used to input passwords on +// login screen. + +// If permitted_layouts is not NULL, it must contain all layouts for the +// language, that can be used at login screen. +// +static const struct SomeLatinKeyboardLanguageList { + const char* lang; + const KBDList* permitted_layouts; +} kHasLatinKeyboardLanguageList[] = { + {"ca" /* Catalan */, NULL}, + {"cs" /* Czech */, NULL}, + {"da" /* Danish */, NULL}, + {"de" /* German */, NULL}, + {"en" /* English */, NULL}, + {"es" /* Spanish */, NULL}, + {"et" /* Estonian */, NULL}, + {"fi" /* Finnish */, NULL}, + {"fr" /* French */, NULL}, + {"ja" /* Japanese */, &kJPFullLatinKeyboards}, + {"hr" /* Croatian */, NULL}, + {"hu" /* Hungarian */, NULL}, + {"is" /* Icelandic */, NULL}, + {"it" /* Italian */, NULL}, + {"lt" /* Lithuanian */, NULL}, + {"lv" /* Latvian */, NULL}, + {"nb" /* Norwegian (Bokmal) */, NULL}, + {"nl" /* Dutch */, NULL}, + {"pl" /* Polish */, NULL}, + {"pt" /* Portuguese */, NULL}, + {"ro" /* Romanian */, NULL}, + {"sk" /* Slovak */, NULL}, + {"sl" /* Slovenian */, NULL}, + {"sv" /* Swedish */, NULL}, + {"tr" /* Turkish */, NULL}, +}; + +} // namespace + +bool FullLatinKeyboardLayoutChecker::IsFullLatinKeyboard( + const std::string& layout, + const std::string& lang) const { + if (lang.size() < 2) { + return false; + } + + const TwoLetterLanguageCode ll(lang.c_str()); + const std::vector<TwoLetterLanguageCode2KBDList>::const_iterator pos = + std::lower_bound(full_latin_keyboard_languages_.begin(), + full_latin_keyboard_languages_.end(), + ll); + + if (pos == full_latin_keyboard_languages_.end()) + return false; + + if (pos->lang != ll) + return false; + + const KBDList* kbdlist = + kHasLatinKeyboardLanguageList[pos->index].permitted_layouts; + + if (kbdlist == NULL) + return true; + + for (size_t i = 0; i < kbdlist->size; ++i) + if (strcmp(layout.c_str(), kbdlist->layouts[i]) == 0) + return true; + + return false; +} + +FullLatinKeyboardLayoutChecker::FullLatinKeyboardLayoutChecker() { + DCHECK(arraysize(kHasLatinKeyboardLanguageList) < + std::numeric_limits<uint16_t>::max()); + + full_latin_keyboard_languages_.reserve( + arraysize(kHasLatinKeyboardLanguageList)); + + for (size_t i = 0; i < arraysize(kHasLatinKeyboardLanguageList); ++i) + full_latin_keyboard_languages_.push_back(TwoLetterLanguageCode2KBDList( + kHasLatinKeyboardLanguageList[i].lang, i)); + + std::sort(full_latin_keyboard_languages_.begin(), + full_latin_keyboard_languages_.end()); +} + +FullLatinKeyboardLayoutChecker::~FullLatinKeyboardLayoutChecker() { +} + +} // namespace input_method +} // namespace chromeos diff --git a/chrome/browser/chromeos/input_method/input_method_manager_impl_ll.h b/chrome/browser/chromeos/input_method/input_method_manager_impl_ll.h new file mode 100644 index 0000000..f670abc --- /dev/null +++ b/chrome/browser/chromeos/input_method/input_method_manager_impl_ll.h @@ -0,0 +1,67 @@ +// Copyright 2013 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef CHROME_BROWSER_CHROMEOS_INPUT_METHOD_INPUT_METHOD_MANAGER_IMPL_LL_H_ +#define CHROME_BROWSER_CHROMEOS_INPUT_METHOD_INPUT_METHOD_MANAGER_IMPL_LL_H_ + +// "Latin Layout" checker: checks if given keyboard layout is "Full Latin Input" + +#include <string> +#include <vector> + +#include "base/strings/string_util.h" + +namespace chromeos { +namespace input_method { + +class TwoLetterLanguageCode { + public: + TwoLetterLanguageCode() : val(0) {} + explicit TwoLetterLanguageCode(const char* lang) + : val(base::ToLowerASCII(lang[0]) * 256 + base::ToLowerASCII(lang[1])) {} + + bool operator<(const TwoLetterLanguageCode& r) const { return val < r.val; } + bool operator!=(const TwoLetterLanguageCode& r) const { return val != r.val; } + + private: + uint16_t val; +}; + +// To keep index small, sizeof(TwoLetterLanguageCode2KBDList) = 4. +class TwoLetterLanguageCode2KBDList { + public: + TwoLetterLanguageCode2KBDList() : index(0) {} + TwoLetterLanguageCode2KBDList(const char* l, const uint16_t i) + : lang(l), index(i) {} + + bool operator<(const TwoLetterLanguageCode2KBDList& r) const { + return lang < r.lang; + } + bool operator<(const TwoLetterLanguageCode& r) const { return lang < r; } + + TwoLetterLanguageCode lang; + + // index in kHasLatinKeyboardLanguageList[] + uint16_t index; +}; + +// For fast lookup "whether this language and layout are among listed in +// kHasLatinKeyboardLanguageList[] or not". +class FullLatinKeyboardLayoutChecker { + public: + FullLatinKeyboardLayoutChecker(); + ~FullLatinKeyboardLayoutChecker(); + + bool IsFullLatinKeyboard(const std::string& layout, + const std::string& lang) const; + + private: + // Sorted vector for fast lookup. + std::vector<TwoLetterLanguageCode2KBDList> full_latin_keyboard_languages_; +}; + +} // namespace input_method +} // namespace chromeos + +#endif // CHROME_BROWSER_CHROMEOS_INPUT_METHOD_INPUT_METHOD_MANAGER_IMPL_LL_H_ diff --git a/chrome/browser/chromeos/input_method/input_method_persistence.cc b/chrome/browser/chromeos/input_method/input_method_persistence.cc index 9562b23..49809fe 100644 --- a/chrome/browser/chromeos/input_method/input_method_persistence.cc +++ b/chrome/browser/chromeos/input_method/input_method_persistence.cc @@ -4,11 +4,13 @@ #include "chrome/browser/chromeos/input_method/input_method_persistence.h" +#include "base/chromeos/chromeos_version.h" #include "base/logging.h" #include "base/prefs/pref_service.h" #include "chrome/browser/browser_process.h" #include "chrome/browser/chromeos/input_method/input_method_util.h" #include "chrome/browser/chromeos/language_preferences.h" +#include "chrome/browser/prefs/scoped_user_pref_update.h" #include "chrome/browser/profiles/profile.h" #include "chrome/browser/profiles/profile_manager.h" #include "chrome/common/pref_names.h" @@ -25,7 +27,62 @@ void PersistSystemInputMethod(const std::string& input_method) { language_prefs::kPreferredKeyboardLayout, input_method); } -void PersistUserInputMethod(const std::string& input_method) { +// Update user LRU keyboard layout for login screen +static void SetUserLRUInputMethod( + const std::string& input_method, + const chromeos::input_method::InputMethodManager* const manager) { + // Skip if it's not a keyboard layout. Drop input methods including + // extension ones. + if (!InputMethodUtil::IsKeyboardLayout(input_method)) + return; + + PrefService* const local_state = g_browser_process->local_state(); + + Profile* const profile = ProfileManager::GetDefaultProfile(); + + if (profile == NULL) + return; + + if (!manager->IsFullLatinKeyboard(input_method)) + return; + + const std::string username = profile->GetProfileName(); + if (base::chromeos::IsRunningOnChromeOS() && !username.empty() && + !local_state->ReadOnly()) { + bool update_succeed = false; + { + // Updater may have side-effects, therefore we do not replace + // entry while updater exists. + DictionaryPrefUpdate updater(local_state, prefs::kUsersLRUInputMethod); + base::DictionaryValue* const users_lru_input_methods = updater.Get(); + if (users_lru_input_methods) { + users_lru_input_methods->SetStringWithoutPathExpansion(username, + input_method); + update_succeed = true; + } + } + if (!update_succeed) { + // Somehow key kUsersLRUInputMethod has value of invalid type. + // Replace and retry. + local_state->Set(prefs::kUsersLRUInputMethod, base::DictionaryValue()); + + DictionaryPrefUpdate updater(local_state, prefs::kUsersLRUInputMethod); + base::DictionaryValue* const users_lru_input_methods = updater.Get(); + if (users_lru_input_methods) { + users_lru_input_methods->SetStringWithoutPathExpansion(username, + input_method); + update_succeed = true; + } + } + if (!update_succeed) { + DVLOG(1) << "Failed to replace local_state.kUsersLRUInputMethod: '" + << prefs::kUsersLRUInputMethod << "' for '" << username << "'"; + } + } +} + +void PersistUserInputMethod(const std::string& input_method, + InputMethodManager* const manager) { PrefService* user_prefs = NULL; Profile* profile = ProfileManager::GetDefaultProfile(); if (profile) @@ -33,6 +90,8 @@ void PersistUserInputMethod(const std::string& input_method) { if (!user_prefs) return; + SetUserLRUInputMethod(input_method, manager); + const std::string current_input_method_on_pref = user_prefs->GetString(prefs::kLanguageCurrentInputMethod); if (current_input_method_on_pref == input_method) @@ -73,7 +132,7 @@ void InputMethodPersistence::InputMethodChanged( PersistSystemInputMethod(current_input_method); return; case InputMethodManager::STATE_BROWSER_SCREEN: - PersistUserInputMethod(current_input_method); + PersistUserInputMethod(current_input_method, manager); return; case InputMethodManager::STATE_LOCK_SCREEN: // We use a special set of input methods on the screen. Do not update. diff --git a/chrome/browser/chromeos/input_method/mock_input_method_manager.cc b/chrome/browser/chromeos/input_method/mock_input_method_manager.cc index ad18c70..4e5cf82 100644 --- a/chrome/browser/chromeos/input_method/mock_input_method_manager.cc +++ b/chrome/browser/chromeos/input_method/mock_input_method_manager.cc @@ -11,6 +11,7 @@ MockInputMethodManager::MockInputMethodManager() : add_observer_count_(0), remove_observer_count_(0), util_(&delegate_, whitelist_.GetSupportedInputMethods()) { + active_input_method_ids_.push_back("xkb:us::eng"); } MockInputMethodManager::~MockInputMethodManager() { @@ -50,6 +51,11 @@ MockInputMethodManager::GetActiveInputMethods() const { return result.Pass(); } +const std::vector<std::string>& +MockInputMethodManager::GetActiveInputMethodIds() const { + return active_input_method_ids_; +} + size_t MockInputMethodManager::GetNumActiveInputMethods() const { return 1; } @@ -63,6 +69,11 @@ bool MockInputMethodManager::EnableInputMethods( return true; } +bool MockInputMethodManager::EnableInputMethod( + const std::string& new_active_input_method_id) { + return true; +} + bool MockInputMethodManager::MigrateOldInputMethods( std::vector<std::string>* input_method_ids) { return false; @@ -162,5 +173,9 @@ void MockInputMethodManager::set_hardware_keyboard_layout( delegate_.set_hardware_keyboard_layout(value); } +bool MockInputMethodManager::IsFullLatinKeyboard( + const std::string& layout) const { + return true; +} } // namespace input_method } // namespace chromeos diff --git a/chrome/browser/chromeos/input_method/mock_input_method_manager.h b/chrome/browser/chromeos/input_method/mock_input_method_manager.h index e373707..aa001c8 100644 --- a/chrome/browser/chromeos/input_method/mock_input_method_manager.h +++ b/chrome/browser/chromeos/input_method/mock_input_method_manager.h @@ -31,11 +31,15 @@ class MockInputMethodManager : public InputMethodManager { GetSupportedInputMethods() const OVERRIDE; virtual scoped_ptr<InputMethodDescriptors> GetActiveInputMethods() const OVERRIDE; + virtual const std::vector<std::string>& GetActiveInputMethodIds() const + OVERRIDE; virtual size_t GetNumActiveInputMethods() const OVERRIDE; virtual void EnableLayouts(const std::string& language_code, const std::string& initial_layout) OVERRIDE; virtual bool EnableInputMethods( const std::vector<std::string>& new_active_input_method_ids) OVERRIDE; + virtual bool EnableInputMethod( + const std::string& new_active_input_method_id) OVERRIDE; virtual bool MigrateOldInputMethods( std::vector<std::string>* input_method_ids) OVERRIDE; virtual bool MigrateKoreanKeyboard( @@ -68,6 +72,7 @@ class MockInputMethodManager : public InputMethodManager { virtual InputMethodUtil* GetInputMethodUtil() OVERRIDE; virtual ComponentExtensionIMEManager* GetComponentExtensionIMEManager() OVERRIDE; + virtual bool IsFullLatinKeyboard(const std::string& layout) const OVERRIDE; // Sets an input method ID which will be returned by GetCurrentInputMethod(). void SetCurrentInputMethodId(const std::string& input_method_id) { @@ -91,6 +96,9 @@ class MockInputMethodManager : public InputMethodManager { InputMethodUtil util_; MockXKeyboard xkeyboard_; + // The active input method ids cache (actually default only) + std::vector<std::string> active_input_method_ids_; + DISALLOW_COPY_AND_ASSIGN(MockInputMethodManager); }; diff --git a/chrome/browser/prefs/browser_prefs.cc b/chrome/browser/prefs/browser_prefs.cc index 14cc6a7..5e90827 100644 --- a/chrome/browser/prefs/browser_prefs.cc +++ b/chrome/browser/prefs/browser_prefs.cc @@ -145,6 +145,7 @@ #include "chrome/browser/chromeos/status/data_promo_notification.h" #include "chrome/browser/chromeos/system/automatic_reboot_manager.h" #include "chrome/browser/extensions/api/enterprise_platform_keys_private/enterprise_platform_keys_private_api.h" +#include "chrome/browser/ui/webui/chromeos/login/signin_screen_handler.h" #else #include "chrome/browser/extensions/default_apps.h" #endif @@ -262,6 +263,7 @@ void RegisterLocalState(PrefRegistrySimple* registry) { chromeos::proxy_config::RegisterPrefs(registry); chromeos::RegisterDisplayLocalStatePrefs(registry); chromeos::ServicesCustomizationDocument::RegisterPrefs(registry); + chromeos::SigninScreenHandler::RegisterPrefs(registry); chromeos::system::AutomaticRebootManager::RegisterPrefs(registry); chromeos::UserImageManager::RegisterPrefs(registry); chromeos::UserManager::RegisterPrefs(registry); diff --git a/chrome/browser/ui/webui/chromeos/login/signin_screen_handler.cc b/chrome/browser/ui/webui/chromeos/login/signin_screen_handler.cc index adfeb11..55197bf 100644 --- a/chrome/browser/ui/webui/chromeos/login/signin_screen_handler.cc +++ b/chrome/browser/ui/webui/chromeos/login/signin_screen_handler.cc @@ -5,11 +5,13 @@ #include "chrome/browser/ui/webui/chromeos/login/signin_screen_handler.h" #include "base/callback.h" +#include "base/chromeos/chromeos_version.h" #include "base/command_line.h" #include "base/debug/trace_event.h" #include "base/logging.h" #include "base/memory/scoped_ptr.h" #include "base/metrics/histogram.h" +#include "base/prefs/pref_registry_simple.h" #include "base/prefs/pref_service.h" #include "base/strings/string16.h" #include "base/strings/string_util.h" @@ -20,6 +22,7 @@ #include "chrome/browser/browser_shutdown.h" #include "chrome/browser/chrome_notification_types.h" #include "chrome/browser/chromeos/app_mode/kiosk_app_manager.h" +#include "chrome/browser/chromeos/input_method/input_method_util.h" #include "chrome/browser/chromeos/kiosk_mode/kiosk_mode_settings.h" #include "chrome/browser/chromeos/login/hwid_checker.h" #include "chrome/browser/chromeos/login/login_display_host_impl.h" @@ -32,6 +35,7 @@ #include "chrome/browser/chromeos/settings/cros_settings.h" #include "chrome/browser/io_thread.h" #include "chrome/browser/policy/browser_policy_connector.h" +#include "chrome/browser/prefs/scoped_user_pref_update.h" #include "chrome/browser/profiles/profile.h" #include "chrome/browser/ui/webui/chromeos/login/error_screen_handler.h" #include "chrome/browser/ui/webui/chromeos/login/native_window_delegate.h" @@ -103,6 +107,12 @@ void ClearDnsCache(IOThread* io_thread) { io_thread->ClearHostCache(); } +static bool Contains(const std::vector<std::string>& container, + const std::string& value) { + return std::find(container.begin(), container.end(), value) != + container.end(); +} + } // namespace namespace chromeos { @@ -312,6 +322,59 @@ void RecordNetworkPortalDetectorStats(const std::string& service_path) { } } +static bool SetUserInputMethodImpl( + const std::string& username, + chromeos::input_method::InputMethodManager* manager) { + PrefService* const local_state = g_browser_process->local_state(); + + const base::DictionaryValue* users_lru_input_methods = + local_state->GetDictionary(prefs::kUsersLRUInputMethod); + + if (users_lru_input_methods == NULL) { + DLOG(WARNING) << "SetUserInputMethod('" << username + << "'): no kUsersLRUInputMethod"; + return false; + } + + std::string input_method; + + if (!users_lru_input_methods->GetStringWithoutPathExpansion(username, + &input_method)) { + DLOG(INFO) << "SetUserInputMethod('" << username + << "'): no input method for this user"; + return false; + } + + if (input_method.empty()) + return false; + + if (!manager->IsFullLatinKeyboard(input_method)) { + LOG(WARNING) << "SetUserInputMethod('" << username + << "'): stored user LRU input method '" << input_method + << "' is no longer Full Latin Keyboard Language" + << " (entry dropped). Use hardware default instead."; + + DictionaryPrefUpdate updater(local_state, prefs::kUsersLRUInputMethod); + + base::DictionaryValue* const users_lru_input_methods = updater.Get(); + if (users_lru_input_methods != NULL) { + users_lru_input_methods->SetStringWithoutPathExpansion(username, ""); + } + return false; + } + + if (!Contains(manager->GetActiveInputMethodIds(), input_method)) { + if (!manager->EnableInputMethod(input_method)) { + DLOG(ERROR) << "SigninScreenHandler::SetUserInputMethod('" << username + << "'): user input method '" << input_method + << "' is not enabled and enabling failed (ignored!)."; + } + } + manager->ChangeInputMethod(input_method); + + return true; +} + } // namespace // SigninScreenHandler implementation ------------------------------------------ @@ -814,6 +877,10 @@ void SigninScreenHandler::RegisterMessages() { &SigninScreenHandler::HandleUpdateOfflineLogin); } +void SigninScreenHandler::RegisterPrefs(PrefRegistrySimple* registry) { + registry->RegisterDictionaryPref(prefs::kUsersLRUInputMethod); +} + void SigninScreenHandler::HandleGetUsers() { SendUserList(false); } @@ -970,6 +1037,35 @@ void SigninScreenHandler::OnDnsCleared() { ShowSigninScreenIfReady(); } +void SigninScreenHandler::SetUserInputMethodHWDefault() { + chromeos::input_method::InputMethodManager* manager = + chromeos::input_method::InputMethodManager::Get(); + manager->ChangeInputMethod( + manager->GetInputMethodUtil()->GetHardwareInputMethodId()); +} + +// Update keyboard layout to least recently used by the user. +void SigninScreenHandler::SetUserInputMethod(const std::string& username) { + chromeos::input_method::InputMethodManager* const manager = + chromeos::input_method::InputMethodManager::Get(); + + const chromeos::input_method::InputMethodUtil& ime_util = + *manager->GetInputMethodUtil(); + + const bool succeed = SetUserInputMethodImpl(username, manager); + + // This is also a case when LRU layout is set only for a few local users, + // thus others need to be switched to default locale. + // Otherwise they will end up using another user's locale to log in. + if (!succeed) { + DLOG(INFO) << "SetUserInputMethod('" << username + << "'): failed to set user layout. Switching to default '" + << ime_util.GetHardwareInputMethodId() << "'"; + + SetUserInputMethodHWDefault(); + } +} + void SigninScreenHandler::ShowSigninScreenIfReady() { if (!dns_cleared_ || !cookies_cleared_ || !delegate_) return; @@ -991,6 +1087,10 @@ void SigninScreenHandler::ShowSigninScreenIfReady() { else delegate_->LoadWallpaper(email_); + // Set Least Recently Used input method for the user. + if (!email_.empty()) + SetUserInputMethod(email_); + LoadAuthExtension(!gaia_silent_load_, false, false); UpdateUIState(UI_STATE_GAIA_SIGNIN, NULL); @@ -1210,6 +1310,7 @@ void SigninScreenHandler::HandleShowAddUser(const base::ListValue* args) { &SigninScreenHandler::ShowSigninScreenIfReady, weak_factory_.GetWeakPtr())); } + SetUserInputMethodHWDefault(); } void SigninScreenHandler::HandleToggleEnrollmentScreen() { diff --git a/chrome/browser/ui/webui/chromeos/login/signin_screen_handler.h b/chrome/browser/ui/webui/chromeos/login/signin_screen_handler.h index aea2d03..5768ab2 100644 --- a/chrome/browser/ui/webui/chromeos/login/signin_screen_handler.h +++ b/chrome/browser/ui/webui/chromeos/login/signin_screen_handler.h @@ -193,6 +193,9 @@ class SigninScreenHandler virtual void UpdateState(NetworkStateInformer::State state, ErrorScreenActor::ErrorReason reason) OVERRIDE; + // Required Local State preferences. + static void RegisterPrefs(PrefRegistrySimple* registry); + private: enum UIState { UI_STATE_UNKNOWN = 0, @@ -379,6 +382,12 @@ class SigninScreenHandler // Attempts login for test. void SubmitLoginFormForTest(); + // Update current input method (namely keyboard layout) to LRU by this user. + void SetUserInputMethod(const std::string& username); + + // Update current input method to HW default. + void SetUserInputMethodHWDefault(); + // Current UI state of the signin screen. UIState ui_state_; diff --git a/chrome/chrome_browser_chromeos.gypi b/chrome/chrome_browser_chromeos.gypi index c891274..08024d6 100644 --- a/chrome/chrome_browser_chromeos.gypi +++ b/chrome/chrome_browser_chromeos.gypi @@ -391,6 +391,8 @@ 'browser/chromeos/input_method/input_method_engine.h', 'browser/chromeos/input_method/input_method_manager_impl.cc', 'browser/chromeos/input_method/input_method_manager_impl.h', + 'browser/chromeos/input_method/input_method_manager_impl_ll.cc', + 'browser/chromeos/input_method/input_method_manager_impl_ll.h', 'browser/chromeos/input_method/input_method_persistence.cc', 'browser/chromeos/input_method/input_method_persistence.h', 'browser/chromeos/input_method/input_method_util.cc', diff --git a/chrome/common/pref_names.cc b/chrome/common/pref_names.cc index 78702ba..1e8eaf7 100644 --- a/chrome/common/pref_names.cc +++ b/chrome/common/pref_names.cc @@ -2122,6 +2122,10 @@ const char kDeviceEnrollmentAutoStart[] = "enrollment.auto_start"; // Whether the user may exit enrollment. const char kDeviceEnrollmentCanExit[] = "enrollment.can_exit"; + +// Dictionary of per-user Least Recently Used input method (used at login +// screen). +extern const char kUsersLRUInputMethod[] = "UsersLRUInputMethod"; #endif // Whether there is a Flash version installed that supports clearing LSO data. diff --git a/chrome/common/pref_names.h b/chrome/common/pref_names.h index 6d1d322..e128646 100644 --- a/chrome/common/pref_names.h +++ b/chrome/common/pref_names.h @@ -773,6 +773,7 @@ extern const char kDeviceRobotAnyApiRefreshToken[]; extern const char kDeviceEnrollmentRequisition[]; extern const char kDeviceEnrollmentAutoStart[]; extern const char kDeviceEnrollmentCanExit[]; +extern const char kUsersLRUInputMethod[]; #endif extern const char kClearPluginLSODataEnabled[]; diff --git a/chromeos/ime/input_method_manager.h b/chromeos/ime/input_method_manager.h index bfeacf6..e2d38dd 100644 --- a/chromeos/ime/input_method_manager.h +++ b/chromeos/ime/input_method_manager.h @@ -98,6 +98,11 @@ class CHROMEOS_EXPORT InputMethodManager { // extension input methods. virtual scoped_ptr<InputMethodDescriptors> GetActiveInputMethods() const = 0; + // Returns the list of input methods we can select (i.e. active) including + // extension input methods. + // The same as GetActiveInputMethods but returns reference to internal list. + virtual const std::vector<std::string>& GetActiveInputMethodIds() const = 0; + // Returns the number of active input methods including extension input // methods. virtual size_t GetNumActiveInputMethods() const = 0; @@ -125,6 +130,11 @@ class CHROMEOS_EXPORT InputMethodManager { virtual bool EnableInputMethods( const std::vector<std::string>& new_active_input_method_ids) = 0; + // Adds one entry to the list of active input method IDs, and then starts or + // stops the system input method framework as needed. + virtual bool EnableInputMethod( + const std::string& new_active_input_method_id) = 0; + // Remaps old input methods like "mozc" to new input methods. Return true if // at least one IME is migrated. // TODO(nona): Remove this function after few milestones are passed. @@ -185,6 +195,9 @@ class CHROMEOS_EXPORT InputMethodManager { // Switches to an input method (or keyboard layout) which is associated with // the |accelerator|. virtual bool SwitchInputMethod(const ui::Accelerator& accelerator) = 0; + + // If keyboard layout can be uset at login screen + virtual bool IsFullLatinKeyboard(const std::string& layout) const = 0; }; } // namespace input_method diff --git a/chromeos/ime/input_methods.txt b/chromeos/ime/input_methods.txt index 85ee9b93..213ea96 100644 --- a/chromeos/ime/input_methods.txt +++ b/chromeos/ime/input_methods.txt @@ -56,6 +56,15 @@ # XKB layout), you should also update IsMod3UsedByCurrentInputMethod() method # in chrome/browser/ui/ash/event_rewriter.cc. Otherwise, Mod3Mask might be # removed unexpectedly by the rewriter. +# +# If you add a new language such that some of its layouts can be used at +# signin screen (e.g. it is "Full Latin Keyboard Layout" therefore allowing +# input of gmail password), you should also update +# kHasLatinKeyboardLanguageList[] in +# chrome/browser/chromeos/input_method/input_method_manager_impl_ll.cc +# +# If you add a new keyboard layout for existing language, please ensure +# that information in kHasLatinKeyboardLanguageList[] is still correct. # U.S. English xkb:us::eng us en-US |