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