Index: chrome/browser/chromeos/preferences.cc |
diff --git a/chrome/browser/chromeos/preferences.cc b/chrome/browser/chromeos/preferences.cc |
index d0e04df2792ce1d2af8709b4bf1f57bad55f0e96..8c32670c3afd8a8c6f940de1bc91a323ce1347a4 100644 |
--- a/chrome/browser/chromeos/preferences.cc |
+++ b/chrome/browser/chromeos/preferences.cc |
@@ -4,7 +4,7 @@ |
#include "chrome/browser/chromeos/preferences.h" |
-#include <vector> |
+#include <algorithm> |
#include "ash/autoclick/autoclick_controller.h" |
#include "ash/magnifier/magnifier_constants.h" |
@@ -32,6 +32,7 @@ |
#include "chrome/common/chrome_switches.h" |
#include "chrome/common/pref_names.h" |
#include "chromeos/chromeos_switches.h" |
+#include "chromeos/ime/component_extension_ime_manager.h" |
#include "chromeos/ime/extension_ime_util.h" |
#include "chromeos/ime/ime_keyboard.h" |
#include "chromeos/ime/input_method_manager.h" |
@@ -39,14 +40,102 @@ |
#include "components/feedback/tracing_manager.h" |
#include "components/pref_registry/pref_registry_syncable.h" |
#include "third_party/icu/source/i18n/unicode/timezone.h" |
+#include "ui/base/l10n/l10n_util.h" |
#include "ui/events/event_constants.h" |
#include "ui/events/event_utils.h" |
#include "url/gurl.h" |
namespace chromeos { |
+namespace { |
+ |
static const char kFallbackInputMethodLocale[] = "en-US"; |
+// Removes unsupported languages from |values|. |
+void CheckLanguages(std::vector<std::string>& values) { |
+ std::vector<std::string>::iterator iter = values.begin(); |
+ while (iter != values.end()) { |
+ std::string locale = *iter; |
+ if (l10n_util::CheckAndResolveLocale(locale, &locale) && |
+ locale == *iter) |
+ ++iter; |
+ else |
+ iter = values.erase(iter); |
+ } |
+} |
+ |
+// Removes unsupported input method IDs from |values|. |
+void CheckInputMethodIDs( |
+ std::vector<std::string>& values, |
+ const input_method::InputMethodDescriptors& supported) { |
+ // Convert legacay descriptors to input method extension IDs. |
+ std::vector<std::string> input_method_ids; |
+ for (size_t i = 0; i < input_method_ids.size(); i++) { |
+ input_method_ids.push_back( |
+ extension_ime_util::GetInputMethodIDByEngineID(supported[i].id())); |
+ } |
+ |
+ // Remove values that aren't in the list of input method IDs. |
+ std::vector<std::string>::iterator value_iter = values.begin(); |
+ while (value_iter != values.end()) { |
+ if (std::find(input_method_ids.begin(), |
+ input_method_ids.end(), |
+ *value_iter) != input_method_ids.end()) { |
+ ++value_iter; |
+ } else { |
+ value_iter = values.erase(value_iter); |
+ } |
+ } |
+} |
+ |
+// Returns the result of merging supported tokens from the CSV string |
+// |new_value| into |old_value| for the given pref. Quadratic runtime; use only |
+// for small lists. |
+std::string MergeCSVPrefs(const std::string& old_value, |
+ const std::string& new_value, |
+ const std::string& pref_name) { |
+ std::vector<std::string> old_tokens; |
+ std::vector<std::string> new_tokens; |
+ |
+ base::SplitString(old_value, ',', &old_tokens); |
+ base::SplitString(new_value, ',', &new_tokens); |
+ |
+ if (pref_name == prefs::kLanguagePreferredLanguages) { |
+ CheckLanguages(new_tokens); |
+ } else if (pref_name == prefs::kLanguagePreloadEngines || |
+ pref_name == prefs::kLanguageEnabledExtensionImes) { |
+ input_method::InputMethodManager* manager = |
+ input_method::InputMethodManager::Get(); |
+ // Supported input methods. |
+ scoped_ptr<input_method::InputMethodDescriptors> descriptors; |
+ |
+ if (pref_name == prefs::kLanguagePreloadEngines) { |
+ // Set the known input methods. |
+ descriptors = manager->GetSupportedInputMethods(); |
+ // Add the available component extension IMEs. |
+ ComponentExtensionIMEManager* component_extension_manager = |
+ input_method::InputMethodManager::Get()-> |
+ GetComponentExtensionIMEManager(); |
+ if (component_extension_manager->IsInitialized()) { |
+ input_method::InputMethodDescriptors component_descriptors = |
+ component_extension_manager->GetAllIMEAsInputMethodDescriptor(); |
+ descriptors->insert(descriptors->end(), |
+ component_descriptors.begin(), |
+ component_descriptors.end()); |
+ } |
+ } else { |
+ descriptors.reset(new input_method::InputMethodDescriptors); |
+ manager->GetInputMethodExtensions(descriptors.get()); |
+ } |
+ CheckInputMethodIDs(new_tokens, *descriptors); |
+ } else { |
+ NOTREACHED() << "Attempting to merge an invalid preference."; |
+ } |
+ return JoinString(old_tokens, ','); |
+} |
+ |
+} // anonymous namespace |
+ |
Preferences::Preferences() |
: prefs_(NULL), |
input_method_manager_(input_method::InputMethodManager::Get()), |
@@ -213,21 +302,34 @@ 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, |
kFallbackInputMethodLocale, |
user_prefs::PrefRegistrySyncable::UNSYNCABLE_PREF); |
registry->RegisterStringPref( |
+ prefs::kLanguagePreferredLanguagesSyncable, |
+ "", |
+ user_prefs::PrefRegistrySyncable::SYNCABLE_PREF); |
+ registry->RegisterStringPref( |
prefs::kLanguagePreloadEngines, |
hardware_keyboard_id, |
user_prefs::PrefRegistrySyncable::UNSYNCABLE_PREF); |
registry->RegisterStringPref( |
+ prefs::kLanguagePreloadEnginesSyncable, |
+ "", |
+ user_prefs::PrefRegistrySyncable::SYNCABLE_PREF); |
+ registry->RegisterStringPref( |
prefs::kLanguageEnabledExtensionImes, |
"", |
user_prefs::PrefRegistrySyncable::UNSYNCABLE_PREF); |
+ registry->RegisterStringPref( |
+ prefs::kLanguageEnabledExtensionImesSyncable, |
+ "", |
+ user_prefs::PrefRegistrySyncable::SYNCABLE_PREF); |
+ registry->RegisterBooleanPref( |
+ prefs::kLanguageShouldMergeInputMethods, |
+ false, |
+ user_prefs::PrefRegistrySyncable::UNSYNCABLE_PREF); |
registry->RegisterIntegerPref( |
prefs::kLanguageRemapSearchKeyTo, |
@@ -329,9 +431,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_syncable_.Init(prefs::kLanguagePreferredLanguagesSyncable, |
+ prefs, callback); |
preload_engines_.Init(prefs::kLanguagePreloadEngines, prefs, callback); |
+ preload_engines_syncable_.Init(prefs::kLanguagePreloadEnginesSyncable, |
+ prefs, callback); |
enabled_extension_imes_.Init(prefs::kLanguageEnabledExtensionImes, |
prefs, callback); |
+ enabled_extension_imes_syncable_.Init( |
+ prefs::kLanguageEnabledExtensionImesSyncable, prefs, callback); |
current_input_method_.Init(prefs::kLanguageCurrentInputMethod, |
prefs, callback); |
previous_input_method_.Init(prefs::kLanguagePreviousInputMethod, |
@@ -511,7 +621,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 +643,28 @@ void Preferences::ApplyPreferences(ApplyReason reason, |
UpdateAutoRepeatRate(); |
} |
+ if (reason == REASON_PREF_CHANGED && |
+ pref_name == prefs::kLanguagePreferredLanguages) |
+ SetSyncableInputMethodPrefs(); |
+ |
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::kLanguagePreloadEngines) { |
+ if (user_is_active) { |
+ SetLanguageConfigStringListAsCSV( |
+ language_prefs::kGeneralSectionName, |
+ language_prefs::kPreloadEnginesConfigName, |
+ preload_engines_.GetValue()); |
+ } |
+ SetSyncableInputMethodPrefs(); |
} |
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); |
- } |
+ if (user_is_active) |
+ SetEnabledExtensionImes(); |
+ if (reason == REASON_PREF_CHANGED) |
+ SetSyncableInputMethodPrefs(); |
} |
if (user_is_active) { |
@@ -562,6 +677,35 @@ void Preferences::ApplyPreferences(ApplyReason reason, |
void Preferences::OnIsSyncingChanged() { |
DVLOG(1) << "OnIsSyncingChanged"; |
ForceNaturalScrollDefault(); |
+ |
+ if (prefs_->GetBoolean(prefs::kLanguageShouldMergeInputMethods) && |
+ prefs_->IsSyncing()) { |
+ MergeSyncedInputMethods(); |
+ prefs_->SetBoolean(prefs::kLanguageShouldMergeInputMethods, false); |
+ } |
+} |
+ |
+void Preferences::MergeSyncedInputMethods() { |
+ DCHECK(prefs_->GetBoolean(prefs::kLanguageShouldMergeInputMethods)); |
+ |
+ preferred_languages_.SetValue( |
+ MergeCSVPrefs(preferred_languages_.GetValue(), |
+ preferred_languages_syncable_.GetValue(), |
+ prefs::kLanguagePreferredLanguages)); |
+ preload_engines_.SetValue( |
+ MergeCSVPrefs(preload_engines_.GetValue(), |
+ preload_engines_syncable_.GetValue(), |
+ prefs::kLanguagePreloadEngines)); |
+ enabled_extension_imes_.SetValue( |
+ MergeCSVPrefs(enabled_extension_imes_.GetValue(), |
+ enabled_extension_imes_syncable_.GetValue(), |
+ prefs::kLanguageEnabledExtensionImes)); |
+ |
+ SetLanguageConfigStringListAsCSV(language_prefs::kGeneralSectionName, |
+ language_prefs::kPreloadEnginesConfigName, |
+ preload_engines_.GetValue()); |
+ SetEnabledExtensionImes(); |
+ SetSyncableInputMethodPrefs(); |
} |
void Preferences::ForceNaturalScrollDefault() { |
@@ -621,6 +765,34 @@ void Preferences::SetInputMethodList() { |
input_method_manager_->ChangeInputMethod(current_input_method_id); |
} |
+void Preferences::SetEnabledExtensionImes() { |
+ 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); |
+} |
+ |
+void Preferences::SetSyncableInputMethodPrefs() { |
+ // 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 (!prefs_->GetBoolean(prefs::kLanguageShouldMergeInputMethods)) { |
+ preferred_languages_syncable_.SetValue(preferred_languages_.GetValue()); |
+ enabled_extension_imes_syncable_.SetValue( |
+ enabled_extension_imes_.GetValue()); |
+ |
+ // For preload engines, use legacy xkb IDs so the preference can sync |
+ // across Chrome OS and Chromium OS. |
+ std::vector<std::string> engines; |
+ base::SplitString(preload_engines_.GetValue(), ',', &engines); |
+ std::transform(engines.begin(), engines.end(), engines.begin(), |
+ extension_ime_util::MaybeGetLegacyXkbId); |
Shu Chen
2014/06/11 03:54:55
extension_ime_util::MaybeGetLegacyXkbId to get eng
michaelpg
2014/06/28 05:25:28
Done.
|
+ /* for (int i = 0; i < engines.size(); i++) |
+ engines[i] = (engines[i]);*/ |
+ preload_engines_syncable_.SetValue(JoinString(engines, ',')); |
+ } |
+} |
+ |
void Preferences::UpdateAutoRepeatRate() { |
input_method::AutoRepeatRate rate; |
rate.initial_delay_in_ms = xkb_auto_repeat_delay_pref_.GetValue(); |