Chromium Code Reviews| Index: chrome/browser/chromeos/preferences.cc |
| diff --git a/chrome/browser/chromeos/preferences.cc b/chrome/browser/chromeos/preferences.cc |
| index d0e04df2792ce1d2af8709b4bf1f57bad55f0e96..3bbff17074a2d2db822a8d7442454fd3f709c8c8 100644 |
| --- a/chrome/browser/chromeos/preferences.cc |
| +++ b/chrome/browser/chromeos/preferences.cc |
| @@ -45,11 +45,49 @@ |
| namespace chromeos { |
| +namespace { |
| + |
| static const char kFallbackInputMethodLocale[] = "en-US"; |
| +// Returns a copy of |old_value| with any unique CSVs from |new_value| |
| +// appended, a logical union that retains order. Quadratic runtime; use only |
| +// for small lists. |
|
michaelpg
2014/06/04 01:12:02
Why not use ListValues instead of StringValues for
|
| +std::string MergeCSVs(const std::string& old_value, |
| + const std::string& new_value) { |
| + std::string merged; |
| + std::vector<std::string> old_tokens; |
| + std::vector<std::string> new_tokens; |
| + |
| + base::SplitString(old_value, ',', &old_tokens); |
| + base::SplitString(new_value, ',', &new_tokens); |
| + |
| + for (size_t i = 0; i < new_tokens.size(); i++) { |
| + // Skip token if it's already in |old_tokens|. |
| + if (std::find(old_tokens.begin(), old_tokens.end(), new_tokens[i]) == |
| + old_tokens.end()) |
| + old_tokens.push_back(new_tokens[i]); |
| + } |
| + return JoinString(old_tokens, ','); |
| +} |
| + |
| +// Merges one CSV pref into another using MergeCSVs. |
| +void MergeStringPrefs(StringPrefMember& to_pref, |
| + StringPrefMember& from_pref, |
| + const std::string& pref_name) { |
| + std::string to_value = to_pref.GetValue(); |
| + std::string from_value = from_pref.GetValue(); |
| + |
| + std::string merged_value = MergeCSVs(to_value, from_value); |
| + if (merged_value != to_value) |
| + to_pref.SetValue(merged_value); |
| +} |
| + |
| +} // anonymous namespace |
| + |
| Preferences::Preferences() |
| : prefs_(NULL), |
| input_method_manager_(input_method::InputMethodManager::Get()), |
| + should_merge_locale_prefs_(false), |
| user_(NULL), |
| user_is_primary_(false) { |
| // Do not observe shell, if there is no shell instance; e.g., in some unit |
| @@ -61,6 +99,7 @@ Preferences::Preferences() |
| Preferences::Preferences(input_method::InputMethodManager* input_method_manager) |
| : prefs_(NULL), |
| input_method_manager_(input_method_manager), |
| + should_merge_locale_prefs_(false), |
| user_(NULL), |
| user_is_primary_(false) { |
| // Do not observe shell, if there is no shell instance; e.g., in some unit |
| @@ -213,20 +252,29 @@ void Preferences::RegisterProfilePrefs( |
| prefs::kLanguagePreviousInputMethod, |
| "", |
| user_prefs::PrefRegistrySyncable::UNSYNCABLE_PREF); |
| - // We don't sync the list of input methods and preferred languages since a |
| - // user might use two or more devices with different hardware keyboards. |
| - // crosbug.com/15181 |
| registry->RegisterStringPref( |
| prefs::kLanguagePreferredLanguages, |
| + "", |
| + user_prefs::PrefRegistrySyncable::SYNCABLE_PREF); |
| + registry->RegisterStringPref( |
| + prefs::kLanguagePreferredLanguagesLocal, |
|
Alexander Alekseev
2014/06/04 14:20:57
I think it is dangerous to change meaning of exist
|
| kFallbackInputMethodLocale, |
| user_prefs::PrefRegistrySyncable::UNSYNCABLE_PREF); |
| registry->RegisterStringPref( |
| prefs::kLanguagePreloadEngines, |
| + "", |
| + user_prefs::PrefRegistrySyncable::SYNCABLE_PREF); |
| + registry->RegisterStringPref( |
| + prefs::kLanguagePreloadEnginesLocal, |
|
Alexander Alekseev
2014/06/04 14:20:57
The same for engines.
|
| hardware_keyboard_id, |
| user_prefs::PrefRegistrySyncable::UNSYNCABLE_PREF); |
| registry->RegisterStringPref( |
| prefs::kLanguageEnabledExtensionImes, |
| "", |
| + user_prefs::PrefRegistrySyncable::SYNCABLE_PREF); |
| + registry->RegisterStringPref( |
| + prefs::kLanguageEnabledExtensionImesLocal, |
| + "", |
|
Alexander Alekseev
2014/06/04 14:20:57
The same for EnabledExtensionsImes
|
| user_prefs::PrefRegistrySyncable::UNSYNCABLE_PREF); |
| registry->RegisterIntegerPref( |
| @@ -329,9 +377,17 @@ void Preferences::InitUserPrefs(PrefServiceSyncable* prefs) { |
| prefs, callback); |
| touch_hud_projection_enabled_.Init(prefs::kTouchHudProjectionEnabled, |
| prefs, callback); |
| + preferred_languages_.Init(prefs::kLanguagePreferredLanguages, |
| + prefs, callback); |
| + preferred_languages_local_.Init(prefs::kLanguagePreferredLanguagesLocal, |
| + prefs, callback); |
| preload_engines_.Init(prefs::kLanguagePreloadEngines, prefs, callback); |
| + preload_engines_local_.Init(prefs::kLanguagePreloadEnginesLocal, |
| + prefs, callback); |
| enabled_extension_imes_.Init(prefs::kLanguageEnabledExtensionImes, |
| prefs, callback); |
| + enabled_extension_imes_local_.Init(prefs::kLanguageEnabledExtensionImesLocal, |
| + prefs, callback); |
| current_input_method_.Init(prefs::kLanguageCurrentInputMethod, |
| prefs, callback); |
| previous_input_method_.Init(prefs::kLanguagePreviousInputMethod, |
| @@ -388,6 +444,27 @@ void Preferences::ApplyPreferences(ApplyReason reason, |
| UserManager::Get()->GetOwnerEmail() == user_->email(); |
| const bool user_is_active = user_->is_active(); |
| + if (reason == REASON_INITIALIZATION) { |
| + // Check that the global language/input preferences have been set. |
| + if (prefs_->FindPreference(prefs::kLanguagePreferredLanguages)-> |
| + HasUserSetting()) { |
| + // If no local value has been set, this is a pre-existing profile. |
| + if (!prefs_->FindPreference(prefs::kLanguagePreferredLanguagesLocal)-> |
| + HasUserSetting()) { |
| + // Migrate to using local values by copying the global values. |
| + preferred_languages_local_.SetValue(preferred_languages_.GetValue()); |
| + preload_engines_local_.SetValue(preload_engines_.GetValue()); |
|
Alexander Alekseev
2014/06/04 14:23:56
The same as my comment below: the list of supporte
|
| + enabled_extension_imes_local_.SetValue( |
| + enabled_extension_imes_.GetValue()); |
|
Alexander Alekseev
2014/06/04 14:20:57
This is dangerous, as you do not check that remote
|
| + } else { |
| + should_merge_locale_prefs_ = false; |
| + } |
| + } else { |
| + // The global preference hasn't been set, so we need to sync and merge it. |
| + should_merge_locale_prefs_ = true; |
| + } |
| + } |
| + |
| system::TouchpadSettings touchpad_settings; |
| system::MouseSettings mouse_settings; |
| @@ -511,7 +588,9 @@ void Preferences::ApplyPreferences(ApplyReason reason, |
| pref_name == prefs::kTouchHudProjectionEnabled) { |
| if (user_is_active) { |
| const bool enabled = touch_hud_projection_enabled_.GetValue(); |
| - ash::Shell::GetInstance()->SetTouchHudProjectionEnabled(enabled); |
| + // There may not be a shell, e.g., in some unit tests. |
| + if (ash::Shell::HasInstance()) |
| + ash::Shell::GetInstance()->SetTouchHudProjectionEnabled(enabled); |
| } |
| } |
| @@ -531,25 +610,28 @@ void Preferences::ApplyPreferences(ApplyReason reason, |
| UpdateAutoRepeatRate(); |
| } |
| + if (reason == REASON_PREF_CHANGED && |
| + pref_name == prefs::kLanguagePreferredLanguagesLocal) |
| + SetSyncedLocalePrefs(); |
| + |
| if (reason != REASON_PREF_CHANGED && user_is_active) { |
| SetInputMethodList(); |
| - } else if (pref_name == prefs::kLanguagePreloadEngines && user_is_active) { |
| - SetLanguageConfigStringListAsCSV(language_prefs::kGeneralSectionName, |
| - language_prefs::kPreloadEnginesConfigName, |
| - preload_engines_.GetValue()); |
| + } else if (pref_name == prefs::kLanguagePreloadEnginesLocal) { |
| + if (user_is_active) { |
| + SetLanguageConfigStringListAsCSV( |
| + language_prefs::kGeneralSectionName, |
| + language_prefs::kPreloadEnginesConfigName, |
| + preload_engines_local_.GetValue()); |
| + } |
| + SetSyncedLocalePrefs(); |
| } |
| if (reason != REASON_PREF_CHANGED || |
| - pref_name == prefs::kLanguageEnabledExtensionImes) { |
| - if (user_is_active) { |
| - std::string value(enabled_extension_imes_.GetValue()); |
| - |
| - std::vector<std::string> split_values; |
| - if (!value.empty()) |
| - base::SplitString(value, ',', &split_values); |
| - |
| - input_method_manager_->SetEnabledExtensionImes(&split_values); |
| - } |
| + pref_name == prefs::kLanguageEnabledExtensionImesLocal) { |
| + if (user_is_active) |
| + SetEnabledExtensionImes(); |
| + if (reason == REASON_PREF_CHANGED) |
| + SetSyncedLocalePrefs(); |
| } |
| if (user_is_active) { |
| @@ -562,6 +644,25 @@ void Preferences::ApplyPreferences(ApplyReason reason, |
| void Preferences::OnIsSyncingChanged() { |
| DVLOG(1) << "OnIsSyncingChanged"; |
| ForceNaturalScrollDefault(); |
| + |
| + if (should_merge_locale_prefs_ && prefs_->IsSyncing()) { |
| + should_merge_locale_prefs_ = false; |
| + MergeStringPrefs(preferred_languages_local_, |
| + preferred_languages_, |
| + prefs::kLanguagePreferredLanguagesLocal); |
| + MergeStringPrefs(preload_engines_local_, |
| + preload_engines_, |
| + prefs::kLanguagePreloadEnginesLocal); |
| + MergeStringPrefs(enabled_extension_imes_local_, |
| + enabled_extension_imes_, |
| + prefs::kLanguageEnabledExtensionImesLocal); |
| + |
| + SetLanguageConfigStringListAsCSV(language_prefs::kGeneralSectionName, |
| + language_prefs::kPreloadEnginesConfigName, |
| + preload_engines_local_.GetValue()); |
| + SetEnabledExtensionImes(); |
| + SetSyncedLocalePrefs(); |
| + } |
| } |
| void Preferences::ForceNaturalScrollDefault() { |
| @@ -587,7 +688,7 @@ void Preferences::SetLanguageConfigStringListAsCSV(const char* section, |
| // Transfers the xkb id to extension-xkb id. |
| if (input_method_manager_->MigrateInputMethods(&split_values)) |
| - preload_engines_.SetValue(JoinString(split_values, ',')); |
| + preload_engines_local_.SetValue(JoinString(split_values, ',')); |
| if (section == std::string(language_prefs::kGeneralSectionName) && |
| name == std::string(language_prefs::kPreloadEnginesConfigName)) { |
| @@ -597,30 +698,49 @@ void Preferences::SetLanguageConfigStringListAsCSV(const char* section, |
| } |
| void Preferences::SetInputMethodList() { |
| - // When |preload_engines_| are set, InputMethodManager::ChangeInputMethod() |
| - // might be called to change the current input method to the first one in the |
| - // |preload_engines_| list. This also updates previous/current input method |
| - // prefs. That's why GetValue() calls are placed before the |
| - // SetLanguageConfigStringListAsCSV() call below. |
| + // When |preload_engines_local_| are set, |
| + // InputMethodManager::ChangeInputMethod() might be called to change the |
| + // current input method to the first one in the |preload_engines_local_| list. |
| + // This also updates previous/current input method prefs. That's why |
| + // GetValue() calls are placed before the SetLanguageConfigStringListAsCSV() |
| + // call below. |
| const std::string previous_input_method_id = |
| previous_input_method_.GetValue(); |
| const std::string current_input_method_id = current_input_method_.GetValue(); |
| SetLanguageConfigStringListAsCSV(language_prefs::kGeneralSectionName, |
| language_prefs::kPreloadEnginesConfigName, |
| - preload_engines_.GetValue()); |
| - |
| - // ChangeInputMethod() has to be called AFTER the value of |preload_engines_| |
| - // is sent to the InputMethodManager. Otherwise, the ChangeInputMethod request |
| - // might be ignored as an invalid input method ID. The ChangeInputMethod() |
| - // calls are also necessary to restore the previous/current input method prefs |
| - // which could have been modified by the SetLanguageConfigStringListAsCSV call |
| - // above to the original state. |
| + preload_engines_local_.GetValue()); |
| + |
| + // ChangeInputMethod() has to be called AFTER the value of |
| + // |preload_engines_local_| is sent to the InputMethodManager. Otherwise, the |
| + // ChangeInputMethod request might be ignored as an invalid input method ID. |
| + // The ChangeInputMethod() calls are also necessary to restore the |
| + // previous/current input method prefs which could have been modified by the |
| + // SetLanguageConfigStringListAsCSV call above to the original state. |
| if (!previous_input_method_id.empty()) |
| input_method_manager_->ChangeInputMethod(previous_input_method_id); |
| if (!current_input_method_id.empty()) |
| input_method_manager_->ChangeInputMethod(current_input_method_id); |
| } |
| +void Preferences::SetEnabledExtensionImes() { |
| + std::string value(enabled_extension_imes_local_.GetValue()); |
| + std::vector<std::string> split_values; |
| + if (!value.empty()) |
| + base::SplitString(value, ',', &split_values); |
| + input_method_manager_->SetEnabledExtensionImes(&split_values); |
| +} |
| + |
| +void Preferences::SetSyncedLocalePrefs() { |
| + // Set the language and input prefs at the same time. Otherwise, we may, |
| + // e.g., use a stale languages setting but push a new preload engines setting. |
| + if (!should_merge_locale_prefs_) { |
| + preferred_languages_.SetValue(preferred_languages_local_.GetValue()); |
| + preload_engines_.SetValue(preload_engines_local_.GetValue()); |
| + enabled_extension_imes_.SetValue(enabled_extension_imes_local_.GetValue()); |
| + } |
| +} |
| + |
| void Preferences::UpdateAutoRepeatRate() { |
| input_method::AutoRepeatRate rate; |
| rate.initial_delay_in_ms = xkb_auto_repeat_delay_pref_.GetValue(); |