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_persistence.h" 6 7#include "base/logging.h" 8#include "base/prefs/pref_service.h" 9#include "base/prefs/scoped_user_pref_update.h" 10#include "base/sys_info.h" 11#include "chrome/browser/browser_process.h" 12#include "chrome/browser/chromeos/input_method/input_method_util.h" 13#include "chrome/browser/chromeos/language_preferences.h" 14#include "chrome/browser/profiles/profile.h" 15#include "chrome/browser/profiles/profile_manager.h" 16#include "chrome/common/pref_names.h" 17 18namespace chromeos { 19namespace input_method { 20namespace { 21 22void PersistSystemInputMethod(const std::string& input_method) { 23 if (!g_browser_process || !g_browser_process->local_state()) 24 return; 25 26 g_browser_process->local_state()->SetString( 27 language_prefs::kPreferredKeyboardLayout, input_method); 28} 29 30static void SetUserLRUInputMethodPreference(const std::string& username, 31 const std::string& input_method, 32 PrefService* local_state) { 33 if (!username.empty() && !local_state->ReadOnly()) { 34 bool update_succeed = false; 35 { 36 // Updater may have side-effects, therefore we do not replace 37 // entry while updater exists. 38 DictionaryPrefUpdate updater(local_state, prefs::kUsersLRUInputMethod); 39 base::DictionaryValue* const users_lru_input_methods = updater.Get(); 40 if (users_lru_input_methods) { 41 users_lru_input_methods->SetStringWithoutPathExpansion(username, 42 input_method); 43 update_succeed = true; 44 } 45 } 46 if (!update_succeed) { 47 // Somehow key kUsersLRUInputMethod has value of invalid type. 48 // Replace and retry. 49 local_state->Set(prefs::kUsersLRUInputMethod, base::DictionaryValue()); 50 51 DictionaryPrefUpdate updater(local_state, prefs::kUsersLRUInputMethod); 52 base::DictionaryValue* const users_lru_input_methods = updater.Get(); 53 if (users_lru_input_methods) { 54 users_lru_input_methods->SetStringWithoutPathExpansion(username, 55 input_method); 56 update_succeed = true; 57 } 58 } 59 if (!update_succeed) { 60 DVLOG(1) << "Failed to replace local_state.kUsersLRUInputMethod: '" 61 << prefs::kUsersLRUInputMethod << "' for '" << username << "'"; 62 } 63 } 64} 65 66// Update user LRU keyboard layout for login screen 67static void SetUserLRUInputMethod( 68 const std::string& input_method, 69 const chromeos::input_method::InputMethodManager* const manager, 70 Profile* profile) { 71 // Skip if it's not a keyboard layout. Drop input methods including 72 // extension ones. 73 if (!manager->IsLoginKeyboard(input_method)) 74 return; 75 76 if (profile == NULL) 77 return; 78 79 PrefService* const local_state = g_browser_process->local_state(); 80 81 SetUserLRUInputMethodPreference( 82 profile->GetProfileName(), input_method, local_state); 83} 84 85void PersistUserInputMethod(const std::string& input_method, 86 InputMethodManager* const manager) { 87 PrefService* user_prefs = NULL; 88 // Persist the method on a per user basis. Note that the keyboard settings are 89 // stored per user desktop and a visiting window will use the same input 90 // method as the desktop it is on (and not of the owner of the window). 91 Profile* profile = ProfileManager::GetActiveUserProfile(); 92 if (profile) 93 user_prefs = profile->GetPrefs(); 94 if (!user_prefs) 95 return; 96 SetUserLRUInputMethod(input_method, manager, profile); 97 98 const std::string current_input_method_on_pref = 99 user_prefs->GetString(prefs::kLanguageCurrentInputMethod); 100 if (current_input_method_on_pref == input_method) 101 return; 102 103 user_prefs->SetString(prefs::kLanguagePreviousInputMethod, 104 current_input_method_on_pref); 105 user_prefs->SetString(prefs::kLanguageCurrentInputMethod, 106 input_method); 107} 108 109} // namespace 110 111InputMethodPersistence::InputMethodPersistence( 112 InputMethodManager* input_method_manager) 113 : input_method_manager_(input_method_manager), 114 ui_session_(InputMethodManager::STATE_LOGIN_SCREEN) { 115 input_method_manager_->AddObserver(this); 116} 117 118InputMethodPersistence::~InputMethodPersistence() { 119 input_method_manager_->RemoveObserver(this); 120} 121 122void InputMethodPersistence::InputMethodChanged( 123 InputMethodManager* manager, bool show_message) { 124 DCHECK_EQ(input_method_manager_, manager); 125 const std::string current_input_method = 126 manager->GetActiveIMEState()->GetCurrentInputMethod().id(); 127 // Save the new input method id depending on the current browser state. 128 switch (ui_session_) { 129 case InputMethodManager::STATE_LOGIN_SCREEN: 130 if (!manager->IsLoginKeyboard(current_input_method)) { 131 DVLOG(1) << "Only keyboard layouts are supported: " 132 << current_input_method; 133 return; 134 } 135 PersistSystemInputMethod(current_input_method); 136 return; 137 case InputMethodManager::STATE_BROWSER_SCREEN: 138 PersistUserInputMethod(current_input_method, manager); 139 return; 140 case InputMethodManager::STATE_LOCK_SCREEN: 141 // We use a special set of input methods on the screen. Do not update. 142 return; 143 case InputMethodManager::STATE_TERMINATING: 144 return; 145 } 146 NOTREACHED(); 147} 148 149void InputMethodPersistence::OnSessionStateChange( 150 InputMethodManager::UISessionState new_ui_session) { 151 ui_session_ = new_ui_session; 152} 153 154void SetUserLRUInputMethodPreferenceForTesting(const std::string& username, 155 const std::string& input_method, 156 PrefService* const local_state) { 157 SetUserLRUInputMethodPreference(username, input_method, local_state); 158} 159 160} // namespace input_method 161} // namespace chromeos 162