| OLD | NEW |
| 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 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 | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include "chrome/browser/chromeos/input_method/browser_state_monitor.h" | 5 #include "chrome/browser/chromeos/input_method/browser_state_monitor.h" |
| 6 | 6 |
| 7 #include "chrome/browser/browser_process.h" | 7 #include "chrome/browser/browser_process.h" |
| 8 #include "chrome/browser/chromeos/input_method/input_method_util.h" | 8 #include "chrome/browser/chromeos/input_method/input_method_util.h" |
| 9 #include "chrome/browser/chromeos/language_preferences.h" | 9 #include "chrome/browser/chromeos/language_preferences.h" |
| 10 #include "chrome/browser/prefs/pref_service.h" | 10 #include "chrome/browser/prefs/pref_service.h" |
| (...skipping 27 matching lines...) Expand all Loading... |
| 38 content::NotificationService::AllSources()); | 38 content::NotificationService::AllSources()); |
| 39 notification_registrar_.Add(this, | 39 notification_registrar_.Add(this, |
| 40 chrome::NOTIFICATION_SCREEN_LOCK_STATE_CHANGED, | 40 chrome::NOTIFICATION_SCREEN_LOCK_STATE_CHANGED, |
| 41 content::NotificationService::AllSources()); | 41 content::NotificationService::AllSources()); |
| 42 // We should not use APP_EXITING here since logout might be canceled by | 42 // We should not use APP_EXITING here since logout might be canceled by |
| 43 // JavaScript after APP_EXITING is sent (crosbug.com/11055). | 43 // JavaScript after APP_EXITING is sent (crosbug.com/11055). |
| 44 notification_registrar_.Add(this, | 44 notification_registrar_.Add(this, |
| 45 content::NOTIFICATION_APP_TERMINATING, | 45 content::NOTIFICATION_APP_TERMINATING, |
| 46 content::NotificationService::AllSources()); | 46 content::NotificationService::AllSources()); |
| 47 | 47 |
| 48 // TODO(yusukes): Tell the initial state to the manager. | 48 manager_->SetState(state_); |
| 49 manager_->AddObserver(this); | 49 manager_->AddObserver(this); |
| 50 } | 50 } |
| 51 | 51 |
| 52 BrowserStateMonitor::~BrowserStateMonitor() { | 52 BrowserStateMonitor::~BrowserStateMonitor() { |
| 53 manager_->RemoveObserver(this); | 53 manager_->RemoveObserver(this); |
| 54 } | 54 } |
| 55 | 55 |
| 56 void BrowserStateMonitor::SetPrefServiceForTesting(PrefService* pref_service) { |
| 57 pref_service_ = pref_service; |
| 58 } |
| 59 |
| 56 void BrowserStateMonitor::UpdateLocalState( | 60 void BrowserStateMonitor::UpdateLocalState( |
| 57 const std::string& current_input_method) { | 61 const std::string& current_input_method) { |
| 58 if (!InputMethodUtil::IsKeyboardLayout(current_input_method)) { | |
| 59 LOG(ERROR) << "Only keyboard layouts are supported: " | |
| 60 << current_input_method; | |
| 61 return; | |
| 62 } | |
| 63 | |
| 64 if (!g_browser_process || !g_browser_process->local_state()) | 62 if (!g_browser_process || !g_browser_process->local_state()) |
| 65 return; | 63 return; |
| 66 | |
| 67 g_browser_process->local_state()->SetString( | 64 g_browser_process->local_state()->SetString( |
| 68 language_prefs::kPreferredKeyboardLayout, | 65 language_prefs::kPreferredKeyboardLayout, |
| 69 current_input_method); | 66 current_input_method); |
| 70 } | 67 } |
| 71 | 68 |
| 72 void BrowserStateMonitor::UpdateUserPreferences( | 69 void BrowserStateMonitor::UpdateUserPreferences( |
| 73 const std::string& current_input_method) { | 70 const std::string& current_input_method) { |
| 74 InitializePrefMembers(); | 71 InitializePrefMembers(); |
| 75 const std::string current_input_method_on_pref = | 72 const std::string current_input_method_on_pref = |
| 76 current_input_method_pref_.GetValue(); | 73 current_input_method_pref_.GetValue(); |
| 77 if (current_input_method_on_pref == current_input_method) | 74 if (current_input_method_on_pref == current_input_method) |
| 78 return; | 75 return; |
| 79 previous_input_method_pref_.SetValue(current_input_method_on_pref); | 76 previous_input_method_pref_.SetValue(current_input_method_on_pref); |
| 80 current_input_method_pref_.SetValue(current_input_method); | 77 current_input_method_pref_.SetValue(current_input_method); |
| 81 } | 78 } |
| 82 | 79 |
| 83 void BrowserStateMonitor::InputMethodChanged( | 80 void BrowserStateMonitor::InputMethodChanged(InputMethodManager* manager) { |
| 84 InputMethodManager* manager, | |
| 85 const InputMethodDescriptor& current_input_method, | |
| 86 size_t num_active_input_methods) { | |
| 87 DCHECK_EQ(manager_, manager); | 81 DCHECK_EQ(manager_, manager); |
| 82 const std::string current_input_method = |
| 83 manager->GetCurrentInputMethod().id(); |
| 88 // Save the new input method id depending on the current browser state. | 84 // Save the new input method id depending on the current browser state. |
| 89 switch (state_) { | 85 switch (state_) { |
| 90 case InputMethodManager::STATE_LOGIN_SCREEN: | 86 case InputMethodManager::STATE_LOGIN_SCREEN: |
| 91 UpdateLocalState(current_input_method.id()); | 87 if (!InputMethodUtil::IsKeyboardLayout(current_input_method)) { |
| 88 LOG(ERROR) << "Only keyboard layouts are supported: " |
| 89 << current_input_method; |
| 90 return; |
| 91 } |
| 92 UpdateLocalState(current_input_method); |
| 92 return; | 93 return; |
| 93 case InputMethodManager::STATE_BROWSER_SCREEN: | 94 case InputMethodManager::STATE_BROWSER_SCREEN: |
| 94 UpdateUserPreferences(current_input_method.id()); | 95 UpdateUserPreferences(current_input_method); |
| 95 return; | |
| 96 case InputMethodManager::STATE_LOGGING_IN: | |
| 97 // Do not update the prefs since Preferences::NotifyPrefChanged() will | |
| 98 // notify the current/previous input method IDs to the manager. | |
| 99 return; | 96 return; |
| 100 case InputMethodManager::STATE_LOCK_SCREEN: | 97 case InputMethodManager::STATE_LOCK_SCREEN: |
| 101 // We use a special set of input methods on the screen. Do not update. | 98 // We use a special set of input methods on the screen. Do not update. |
| 102 return; | 99 return; |
| 103 case InputMethodManager::STATE_TERMINATING: | 100 case InputMethodManager::STATE_TERMINATING: |
| 104 return; | 101 return; |
| 105 } | 102 } |
| 106 NOTREACHED(); | 103 NOTREACHED(); |
| 107 } | 104 } |
| 108 | 105 |
| 106 void BrowserStateMonitor::InputMethodPropertyChanged( |
| 107 InputMethodManager* manager) {} |
| 108 |
| 109 void BrowserStateMonitor::Observe( | 109 void BrowserStateMonitor::Observe( |
| 110 int type, | 110 int type, |
| 111 const content::NotificationSource& source, | 111 const content::NotificationSource& source, |
| 112 const content::NotificationDetails& details) { | 112 const content::NotificationDetails& details) { |
| 113 switch (type) { | 113 switch (type) { |
| 114 case content::NOTIFICATION_APP_TERMINATING: { | 114 case content::NOTIFICATION_APP_TERMINATING: { |
| 115 SetState(InputMethodManager::STATE_TERMINATING); | 115 SetState(InputMethodManager::STATE_TERMINATING); |
| 116 break; | 116 break; |
| 117 } | 117 } |
| 118 case chrome::NOTIFICATION_LOGIN_USER_CHANGED: { | 118 case chrome::NOTIFICATION_LOGIN_USER_CHANGED: { |
| 119 // The user logged in, but the browser window for user session is not yet | 119 // The user logged in, but the browser window for user session is not yet |
| 120 // ready. An initial input method hasn't been set to the manager. | 120 // ready. An initial input method hasn't been set to the manager. |
| 121 // Note that the notification is also sent when Chrome crashes/restarts. | 121 // Note that the notification is also sent when Chrome crashes/restarts |
| 122 SetState(InputMethodManager::STATE_LOGGING_IN); | 122 // as of writing, but it might be changed in the future (therefore we need |
| 123 // to listen to NOTIFICATION_SESSION_STARTED as well.) |
| 124 VLOG(1) << "Received chrome::NOTIFICATION_LOGIN_USER_CHANGED"; |
| 125 SetState(InputMethodManager::STATE_BROWSER_SCREEN); |
| 123 break; | 126 break; |
| 124 } | 127 } |
| 125 case chrome::NOTIFICATION_SESSION_STARTED: { | 128 case chrome::NOTIFICATION_SESSION_STARTED: { |
| 126 // The user logged in, and the browser window for user session is ready. | 129 // The user logged in, and the browser window for user session is ready. |
| 127 // An initial input method has already been set. | 130 // An initial input method has already been set. |
| 128 // We should NOT call InitializePrefMembers() here since the notification | 131 // We should NOT call InitializePrefMembers() here since the notification |
| 129 // is sent in the PreProfileInit phase in case when Chrome crashes and | 132 // is sent in the PreProfileInit phase in case when Chrome crashes and |
| 130 // restarts. | 133 // restarts. |
| 134 VLOG(1) << "Received chrome::NOTIFICATION_SESSION_STARTED"; |
| 131 SetState(InputMethodManager::STATE_BROWSER_SCREEN); | 135 SetState(InputMethodManager::STATE_BROWSER_SCREEN); |
| 132 break; | 136 break; |
| 133 } | 137 } |
| 134 case chrome::NOTIFICATION_SCREEN_LOCK_STATE_CHANGED: { | 138 case chrome::NOTIFICATION_SCREEN_LOCK_STATE_CHANGED: { |
| 135 const bool is_screen_locked = *content::Details<bool>(details).ptr(); | 139 const bool is_screen_locked = *content::Details<bool>(details).ptr(); |
| 136 SetState(is_screen_locked ? InputMethodManager::STATE_LOCK_SCREEN : | 140 SetState(is_screen_locked ? InputMethodManager::STATE_LOCK_SCREEN : |
| 137 InputMethodManager::STATE_BROWSER_SCREEN); | 141 InputMethodManager::STATE_BROWSER_SCREEN); |
| 138 break; | 142 break; |
| 139 } | 143 } |
| 140 case chrome::NOTIFICATION_PREF_CHANGED: { | 144 case chrome::NOTIFICATION_PREF_CHANGED: { |
| 141 break; // just ignore the notification. | 145 break; // just ignore the notification. |
| 142 } | 146 } |
| 143 default: { | 147 default: { |
| 144 NOTREACHED(); | 148 NOTREACHED(); |
| 145 break; | 149 break; |
| 146 } | 150 } |
| 147 } | 151 } |
| 148 | 152 // Note: browser notifications are sent in the following order. |
| 149 // TODO(yusukes): On R20, we should handle Chrome crash/restart correctly. | |
| 150 // Currently, a wrong input method could be selected when Chrome crashes and | |
| 151 // restarts. | |
| 152 // | 153 // |
| 153 // Normal login sequence: | 154 // Normal login: |
| 154 // 1. chrome::NOTIFICATION_LOGIN_USER_CHANGED is sent. | 155 // 1. chrome::NOTIFICATION_LOGIN_USER_CHANGED is sent. |
| 155 // 2. Preferences::NotifyPrefChanged() is called. preload_engines (which | 156 // 2. Preferences::NotifyPrefChanged() is called. preload_engines (which |
| 156 // might change the current input method) and current/previous input method | 157 // might change the current input method) and current/previous input method |
| 157 // are sent to the manager. | 158 // are sent to the manager. |
| 158 // 3. chrome::NOTIFICATION_SESSION_STARTED is sent. | 159 // 3. chrome::NOTIFICATION_SESSION_STARTED is sent. |
| 159 // | 160 // |
| 160 // Chrome crash/restart (after logging in) sequence: | 161 // Chrome crash/restart (after logging in): |
| 161 // 1. chrome::NOTIFICATION_LOGIN_USER_CHANGED is sent. | 162 // 1. chrome::NOTIFICATION_LOGIN_USER_CHANGED might be sent. |
| 162 // 2. chrome::NOTIFICATION_SESSION_STARTED is sent. | 163 // 2. chrome::NOTIFICATION_SESSION_STARTED is sent. |
| 163 // 3. Preferences::NotifyPrefChanged() is called. preload_engines (which | 164 // 3. Preferences::NotifyPrefChanged() is called. The same things as above |
| 164 // might change the current input method) and current/previous input method | 165 // happen. |
| 165 // are sent to the manager. When preload_engines are sent to the manager, | 166 // |
| 166 // UpdateUserPreferences() might be accidentally called. | 167 // We have to be careful not to overwrite both local and user prefs when |
| 168 // preloaded engine is set. Note that it does not work to do nothing in |
| 169 // InputMethodChanged() between chrome::NOTIFICATION_LOGIN_USER_CHANGED and |
| 170 // chrome::NOTIFICATION_SESSION_STARTED because SESSION_STARTED is sent very |
| 171 // early on Chrome crash/restart. |
| 167 } | 172 } |
| 168 | 173 |
| 169 void BrowserStateMonitor::SetState(InputMethodManager::State new_state) { | 174 void BrowserStateMonitor::SetState(InputMethodManager::State new_state) { |
| 170 const InputMethodManager::State old_state = state_; | 175 const InputMethodManager::State old_state = state_; |
| 171 state_ = new_state; | 176 state_ = new_state; |
| 172 if (old_state != state_) { | 177 if (old_state != state_) |
| 173 // TODO(yusukes): Tell the new state to the manager. | 178 manager_->SetState(state_); |
| 174 } | |
| 175 } | 179 } |
| 176 | 180 |
| 177 void BrowserStateMonitor::InitializePrefMembers() { | 181 void BrowserStateMonitor::InitializePrefMembers() { |
| 178 if (initialized_) | 182 if (initialized_) |
| 179 return; | 183 return; |
| 180 | 184 |
| 181 initialized_ = true; | 185 initialized_ = true; |
| 182 PrefService* pref_service = GetPrefService(); | 186 PrefService* pref_service = pref_service_ ? pref_service_ : GetPrefService(); |
| 183 DCHECK(pref_service); | 187 DCHECK(pref_service); |
| 184 DCHECK_EQ(InputMethodManager::STATE_BROWSER_SCREEN, state_); | 188 DCHECK_EQ(InputMethodManager::STATE_BROWSER_SCREEN, state_); |
| 185 previous_input_method_pref_.Init( | 189 previous_input_method_pref_.Init( |
| 186 prefs::kLanguagePreviousInputMethod, pref_service, this); | 190 prefs::kLanguagePreviousInputMethod, pref_service, this); |
| 187 current_input_method_pref_.Init( | 191 current_input_method_pref_.Init( |
| 188 prefs::kLanguageCurrentInputMethod, pref_service, this); | 192 prefs::kLanguageCurrentInputMethod, pref_service, this); |
| 189 } | 193 } |
| 190 | 194 |
| 191 } // namespace input_method | 195 } // namespace input_method |
| 192 } // namespace chromeos | 196 } // namespace chromeos |
| OLD | NEW |