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 |