Chromium Code Reviews| Index: chrome/browser/chromeos/input_method/browser_state_monitor.cc |
| diff --git a/chrome/browser/chromeos/input_method/browser_state_monitor.cc b/chrome/browser/chromeos/input_method/browser_state_monitor.cc |
| new file mode 100644 |
| index 0000000000000000000000000000000000000000..cc5636e4f9b368cdd2d01c3f1c371cde45bc2a69 |
| --- /dev/null |
| +++ b/chrome/browser/chromeos/input_method/browser_state_monitor.cc |
| @@ -0,0 +1,203 @@ |
| +// Copyright (c) 2012 The Chromium Authors. All rights reserved. |
| +// Use of this source code is governed by a BSD-style license that can be |
| +// found in the LICENSE file. |
| + |
| +#include "chrome/browser/chromeos/input_method/browser_state_monitor.h" |
| + |
| +#include "ash/ash_switches.h" |
| +#include "base/command_line.h" |
| +#include "chrome/browser/browser_process.h" |
| +#include "chrome/browser/chromeos/input_method/input_method_util.h" |
| +#include "chrome/browser/chromeos/language_preferences.h" |
| +#include "chrome/browser/prefs/pref_service.h" |
| +#include "chrome/browser/profiles/profile_manager.h" |
| +#include "chrome/common/chrome_notification_types.h" |
| +#include "chrome/common/pref_names.h" |
| +#include "content/public/browser/notification_service.h" |
| + |
| +namespace chromeos { |
| +namespace input_method { |
| +namespace { |
| + |
| +PrefService* GetPrefService() { |
| + Profile* profile = ProfileManager::GetDefaultProfile(); |
| + if (profile) |
| + return profile->GetPrefs(); |
| + return NULL; |
| +} |
| + |
| +} // namespace |
| + |
| +BrowserStateMonitor::BrowserStateMonitor(InputMethodManager* manager) |
| + : manager_(manager), |
| + state_(InputMethodManager::STATE_LOGIN_SCREEN), |
| + initialized_(false) { |
| + // On R19, when Uber Tray is disabled, the IME status button will update the |
| + // Preferences. |
| + // TODO(yusukes): Remove all Preferences code from the button on R20. |
| + if (CommandLine::ForCurrentProcess()->HasSwitch( |
| + ash::switches::kDisableAshUberTray)) |
| + return; |
| + |
| + notification_registrar_.Add(this, |
| + chrome::NOTIFICATION_LOGIN_USER_CHANGED, |
| + content::NotificationService::AllSources()); |
| + notification_registrar_.Add(this, |
| + chrome::NOTIFICATION_SESSION_STARTED, |
| + content::NotificationService::AllSources()); |
| + notification_registrar_.Add(this, |
| + chrome::NOTIFICATION_SCREEN_LOCK_STATE_CHANGED, |
| + content::NotificationService::AllSources()); |
| + // We should not use APP_EXITING here since logout might be canceled by |
| + // JavaScript after APP_EXITING is sent (crosbug.com/11055). |
| + notification_registrar_.Add(this, |
| + content::NOTIFICATION_APP_TERMINATING, |
| + content::NotificationService::AllSources()); |
| + |
| + // TODO(yusukes): Tell the initial state to the manager. |
| + manager_->AddPreLoginPreferenceObserver(this); |
| + manager_->AddPostLoginPreferenceObserver(this); |
| +} |
| + |
| +BrowserStateMonitor::~BrowserStateMonitor() { |
| + manager_->RemovePostLoginPreferenceObserver(this); |
| + manager_->RemovePreLoginPreferenceObserver(this); |
| +} |
| + |
| +void BrowserStateMonitor::UpdateLocalState( |
| + const std::string& current_input_method) { |
| + if (!InputMethodUtil::IsKeyboardLayout(current_input_method)) { |
| + LOG(ERROR) << "Only keyboard layouts are supported: " |
| + << current_input_method; |
| + return; |
| + } |
| + |
| + if (!g_browser_process || !g_browser_process->local_state()) |
| + return; |
| + |
| + g_browser_process->local_state()->SetString( |
| + language_prefs::kPreferredKeyboardLayout, |
| + current_input_method); |
| +} |
| + |
| +void BrowserStateMonitor::UpdateUserPreferences( |
| + const std::string& current_input_method) { |
| + InitializePrefMembers(); |
| + const std::string current_input_method_on_pref = |
| + current_input_method_pref_.GetValue(); |
| + if (current_input_method_on_pref == current_input_method) |
| + return; |
| + previous_input_method_pref_.SetValue(current_input_method_on_pref); |
| + current_input_method_pref_.SetValue(current_input_method); |
| +} |
| + |
| +void BrowserStateMonitor::PreferenceUpdateNeeded( |
| + input_method::InputMethodManager* manager, |
| + const input_method::InputMethodDescriptor& previous_input_method, |
| + const input_method::InputMethodDescriptor& current_input_method) { |
| + DCHECK_EQ(manager_, manager); |
| + // Save the new input method id depending on the current browser state. |
| + switch (state_) { |
| + case InputMethodManager::STATE_LOGIN_SCREEN: |
| + UpdateLocalState(current_input_method.id()); |
|
Zachary Kuznia
2012/03/26 06:26:07
Does this handle the case where an IME is being us
Yusuke Sato
2012/03/26 06:42:43
Actually Aura version of Chrome OS never enables a
|
| + return; |
| + case InputMethodManager::STATE_BROWSER_SCREEN: |
| + UpdateUserPreferences(current_input_method.id()); |
| + return; |
| + case InputMethodManager::STATE_LOGGING_IN: |
| + // Do not update the prefs since Preferences::NotifyPrefChanged() will |
| + // notify the current/previous input method IDs to the manager. |
| + return; |
| + case InputMethodManager::STATE_LOCK_SCREEN: |
| + // We use a special set of input methods on the screen. Do not update. |
| + return; |
| + case InputMethodManager::STATE_TERMINATING: |
| + return; |
| + } |
| + NOTREACHED(); |
| +} |
| + |
| +void BrowserStateMonitor::Observe( |
| + int type, |
| + const content::NotificationSource& source, |
| + const content::NotificationDetails& details) { |
| + switch (type) { |
| + case content::NOTIFICATION_APP_TERMINATING: { |
| + SetState(InputMethodManager::STATE_TERMINATING); |
| + break; |
| + } |
| + case chrome::NOTIFICATION_LOGIN_USER_CHANGED: { |
| + // The user logged in, but the browser window for user session is not yet |
| + // ready. An initial input method hasn't been set to the manager. |
| + // Note that the notification is also sent when Chrome crashes/restarts. |
| + SetState(InputMethodManager::STATE_LOGGING_IN); |
| + break; |
| + } |
| + case chrome::NOTIFICATION_SESSION_STARTED: { |
| + // The user logged in, and the browser window for user session is ready. |
| + // An initial input method has already been set. |
| + // We should NOT call InitializePrefMembers() here since the notification |
| + // is sent in the PreProfileInit phase in case when Chrome crashes and |
| + // restarts. |
| + SetState(InputMethodManager::STATE_BROWSER_SCREEN); |
| + break; |
| + } |
| + case chrome::NOTIFICATION_SCREEN_LOCK_STATE_CHANGED: { |
| + const bool is_screen_locked = *content::Details<bool>(details).ptr(); |
| + SetState(is_screen_locked ? InputMethodManager::STATE_LOCK_SCREEN : |
| + InputMethodManager::STATE_BROWSER_SCREEN); |
| + break; |
| + } |
| + case chrome::NOTIFICATION_PREF_CHANGED: { |
| + break; // just ignore the notification. |
| + } |
| + default: { |
| + NOTREACHED(); |
| + break; |
| + } |
| + } |
| + |
| + // TODO(yusukes): On R20, we should handle Chrome crash/restart correctly. |
| + // Currently, a wrong input method could be selected when Chrome crashes and |
| + // restarts. |
| + // |
| + // Normal login sequence: |
| + // 1. chrome::NOTIFICATION_LOGIN_USER_CHANGED is sent. |
| + // 2. Preferences::NotifyPrefChanged() is called. preload_engines (which |
| + // might change the current input method) and current/previous input method |
| + // are sent to the manager. |
| + // 3. chrome::NOTIFICATION_SESSION_STARTED is sent. |
| + // |
| + // Chrome crash/restart (after logging in) sequence: |
| + // 1. chrome::NOTIFICATION_LOGIN_USER_CHANGED is sent. |
| + // 2. chrome::NOTIFICATION_SESSION_STARTED is sent. |
| + // 3. Preferences::NotifyPrefChanged() is called. preload_engines (which |
| + // might change the current input method) and current/previous input method |
| + // are sent to the manager. When preload_engines are sent to the manager, |
| + // UpdateUserPreferences() might be accidentally called. |
| +} |
| + |
| +void BrowserStateMonitor::SetState(InputMethodManager::State new_state) { |
| + const InputMethodManager::State old_state = state_; |
| + state_ = new_state; |
| + if (old_state != state_) { |
| + // TODO(yusukes): Tell the new state to the manager. |
| + } |
| +} |
| + |
| +void BrowserStateMonitor::InitializePrefMembers() { |
| + if (initialized_) |
| + return; |
| + |
| + initialized_ = true; |
| + PrefService* pref_service = GetPrefService(); |
| + DCHECK(pref_service); |
| + DCHECK_EQ(InputMethodManager::STATE_BROWSER_SCREEN, state_); |
| + previous_input_method_pref_.Init( |
| + prefs::kLanguagePreviousInputMethod, pref_service, this); |
| + current_input_method_pref_.Init( |
| + prefs::kLanguageCurrentInputMethod, pref_service, this); |
| +} |
| + |
| +} // namespace input_method |
| +} // namespace chromeos |