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