OLD | NEW |
(Empty) | |
| 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/browser_state_monitor.h" |
| 6 |
| 7 #include "ash/ash_switches.h" |
| 8 #include "base/command_line.h" |
| 9 #include "chrome/browser/browser_process.h" |
| 10 #include "chrome/browser/chromeos/input_method/input_method_util.h" |
| 11 #include "chrome/browser/chromeos/language_preferences.h" |
| 12 #include "chrome/browser/prefs/pref_service.h" |
| 13 #include "chrome/browser/profiles/profile_manager.h" |
| 14 #include "chrome/common/chrome_notification_types.h" |
| 15 #include "chrome/common/pref_names.h" |
| 16 #include "content/public/browser/notification_service.h" |
| 17 |
| 18 namespace chromeos { |
| 19 namespace input_method { |
| 20 namespace { |
| 21 |
| 22 PrefService* GetPrefService() { |
| 23 Profile* profile = ProfileManager::GetDefaultProfile(); |
| 24 if (profile) |
| 25 return profile->GetPrefs(); |
| 26 return NULL; |
| 27 } |
| 28 |
| 29 } // namespace |
| 30 |
| 31 BrowserStateMonitor::BrowserStateMonitor(InputMethodManager* manager) |
| 32 : manager_(manager), |
| 33 state_(InputMethodManager::STATE_LOGIN_SCREEN), |
| 34 initialized_(false) { |
| 35 // On R19, when Uber Tray is disabled, the IME status button will update the |
| 36 // Preferences. |
| 37 // TODO(yusukes): Remove all Preferences code from the button on R20. |
| 38 if (CommandLine::ForCurrentProcess()->HasSwitch( |
| 39 ash::switches::kDisableAshUberTray)) |
| 40 return; |
| 41 |
| 42 notification_registrar_.Add(this, |
| 43 chrome::NOTIFICATION_LOGIN_USER_CHANGED, |
| 44 content::NotificationService::AllSources()); |
| 45 notification_registrar_.Add(this, |
| 46 chrome::NOTIFICATION_SESSION_STARTED, |
| 47 content::NotificationService::AllSources()); |
| 48 notification_registrar_.Add(this, |
| 49 chrome::NOTIFICATION_SCREEN_LOCK_STATE_CHANGED, |
| 50 content::NotificationService::AllSources()); |
| 51 // We should not use APP_EXITING here since logout might be canceled by |
| 52 // JavaScript after APP_EXITING is sent (crosbug.com/11055). |
| 53 notification_registrar_.Add(this, |
| 54 content::NOTIFICATION_APP_TERMINATING, |
| 55 content::NotificationService::AllSources()); |
| 56 |
| 57 // TODO(yusukes): Tell the initial state to the manager. |
| 58 manager_->AddPreLoginPreferenceObserver(this); |
| 59 manager_->AddPostLoginPreferenceObserver(this); |
| 60 } |
| 61 |
| 62 BrowserStateMonitor::~BrowserStateMonitor() { |
| 63 manager_->RemovePostLoginPreferenceObserver(this); |
| 64 manager_->RemovePreLoginPreferenceObserver(this); |
| 65 } |
| 66 |
| 67 void BrowserStateMonitor::UpdateLocalState( |
| 68 const std::string& current_input_method) { |
| 69 if (!InputMethodUtil::IsKeyboardLayout(current_input_method)) { |
| 70 LOG(ERROR) << "Only keyboard layouts are supported: " |
| 71 << current_input_method; |
| 72 return; |
| 73 } |
| 74 |
| 75 if (!g_browser_process || !g_browser_process->local_state()) |
| 76 return; |
| 77 |
| 78 g_browser_process->local_state()->SetString( |
| 79 language_prefs::kPreferredKeyboardLayout, |
| 80 current_input_method); |
| 81 } |
| 82 |
| 83 void BrowserStateMonitor::UpdateUserPreferences( |
| 84 const std::string& current_input_method) { |
| 85 InitializePrefMembers(); |
| 86 const std::string current_input_method_on_pref = |
| 87 current_input_method_pref_.GetValue(); |
| 88 if (current_input_method_on_pref == current_input_method) |
| 89 return; |
| 90 previous_input_method_pref_.SetValue(current_input_method_on_pref); |
| 91 current_input_method_pref_.SetValue(current_input_method); |
| 92 } |
| 93 |
| 94 void BrowserStateMonitor::PreferenceUpdateNeeded( |
| 95 input_method::InputMethodManager* manager, |
| 96 const input_method::InputMethodDescriptor& previous_input_method, |
| 97 const input_method::InputMethodDescriptor& current_input_method) { |
| 98 DCHECK_EQ(manager_, manager); |
| 99 // Save the new input method id depending on the current browser state. |
| 100 switch (state_) { |
| 101 case InputMethodManager::STATE_LOGIN_SCREEN: |
| 102 UpdateLocalState(current_input_method.id()); |
| 103 return; |
| 104 case InputMethodManager::STATE_BROWSER_SCREEN: |
| 105 UpdateUserPreferences(current_input_method.id()); |
| 106 return; |
| 107 case InputMethodManager::STATE_LOGGING_IN: |
| 108 // Do not update the prefs since Preferences::NotifyPrefChanged() will |
| 109 // notify the current/previous input method IDs to the manager. |
| 110 return; |
| 111 case InputMethodManager::STATE_LOCK_SCREEN: |
| 112 // We use a special set of input methods on the screen. Do not update. |
| 113 return; |
| 114 case InputMethodManager::STATE_TERMINATING: |
| 115 return; |
| 116 } |
| 117 NOTREACHED(); |
| 118 } |
| 119 |
| 120 void BrowserStateMonitor::Observe( |
| 121 int type, |
| 122 const content::NotificationSource& source, |
| 123 const content::NotificationDetails& details) { |
| 124 switch (type) { |
| 125 case content::NOTIFICATION_APP_TERMINATING: { |
| 126 SetState(InputMethodManager::STATE_TERMINATING); |
| 127 break; |
| 128 } |
| 129 case chrome::NOTIFICATION_LOGIN_USER_CHANGED: { |
| 130 // The user logged in, but the browser window for user session is not yet |
| 131 // ready. An initial input method hasn't been set to the manager. |
| 132 // Note that the notification is also sent when Chrome crashes/restarts. |
| 133 SetState(InputMethodManager::STATE_LOGGING_IN); |
| 134 break; |
| 135 } |
| 136 case chrome::NOTIFICATION_SESSION_STARTED: { |
| 137 // The user logged in, and the browser window for user session is ready. |
| 138 // An initial input method has already been set. |
| 139 // We should NOT call InitializePrefMembers() here since the notification |
| 140 // is sent in the PreProfileInit phase in case when Chrome crashes and |
| 141 // restarts. |
| 142 SetState(InputMethodManager::STATE_BROWSER_SCREEN); |
| 143 break; |
| 144 } |
| 145 case chrome::NOTIFICATION_SCREEN_LOCK_STATE_CHANGED: { |
| 146 const bool is_screen_locked = *content::Details<bool>(details).ptr(); |
| 147 SetState(is_screen_locked ? InputMethodManager::STATE_LOCK_SCREEN : |
| 148 InputMethodManager::STATE_BROWSER_SCREEN); |
| 149 break; |
| 150 } |
| 151 case chrome::NOTIFICATION_PREF_CHANGED: { |
| 152 break; // just ignore the notification. |
| 153 } |
| 154 default: { |
| 155 NOTREACHED(); |
| 156 break; |
| 157 } |
| 158 } |
| 159 |
| 160 // TODO(yusukes): On R20, we should handle Chrome crash/restart correctly. |
| 161 // Currently, a wrong input method could be selected when Chrome crashes and |
| 162 // restarts. |
| 163 // |
| 164 // Normal login sequence: |
| 165 // 1. chrome::NOTIFICATION_LOGIN_USER_CHANGED is sent. |
| 166 // 2. Preferences::NotifyPrefChanged() is called. preload_engines (which |
| 167 // might change the current input method) and current/previous input method |
| 168 // are sent to the manager. |
| 169 // 3. chrome::NOTIFICATION_SESSION_STARTED is sent. |
| 170 // |
| 171 // Chrome crash/restart (after logging in) sequence: |
| 172 // 1. chrome::NOTIFICATION_LOGIN_USER_CHANGED is sent. |
| 173 // 2. chrome::NOTIFICATION_SESSION_STARTED is sent. |
| 174 // 3. Preferences::NotifyPrefChanged() is called. preload_engines (which |
| 175 // might change the current input method) and current/previous input method |
| 176 // are sent to the manager. When preload_engines are sent to the manager, |
| 177 // UpdateUserPreferences() might be accidentally called. |
| 178 } |
| 179 |
| 180 void BrowserStateMonitor::SetState(InputMethodManager::State new_state) { |
| 181 const InputMethodManager::State old_state = state_; |
| 182 state_ = new_state; |
| 183 if (old_state != state_) { |
| 184 // TODO(yusukes): Tell the new state to the manager. |
| 185 } |
| 186 } |
| 187 |
| 188 void BrowserStateMonitor::InitializePrefMembers() { |
| 189 if (initialized_) |
| 190 return; |
| 191 |
| 192 initialized_ = true; |
| 193 PrefService* pref_service = GetPrefService(); |
| 194 DCHECK(pref_service); |
| 195 DCHECK_EQ(InputMethodManager::STATE_BROWSER_SCREEN, state_); |
| 196 previous_input_method_pref_.Init( |
| 197 prefs::kLanguagePreviousInputMethod, pref_service, this); |
| 198 current_input_method_pref_.Init( |
| 199 prefs::kLanguageCurrentInputMethod, pref_service, this); |
| 200 } |
| 201 |
| 202 } // namespace input_method |
| 203 } // namespace chromeos |
OLD | NEW |