| Index: chrome/browser/chromeos/preferences.cc
|
| diff --git a/chrome/browser/chromeos/preferences.cc b/chrome/browser/chromeos/preferences.cc
|
| index fd7b1940c28d75f0d88f82b096e378850df4ab22..1de6d9e19193091f393b15590a058d75ee3bf23c 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"
|
| @@ -31,6 +31,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"
|
| @@ -38,20 +39,132 @@
|
| #include "components/feedback/tracing_manager.h"
|
| #include "components/pref_registry/pref_registry_syncable.h"
|
| #include "components/user_manager/user.h"
|
| +#include "content/public/browser/browser_thread.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";
|
|
|
| +// Checks input method IDs, converting engine IDs to input method IDs and
|
| +// removing unsupported IDs from |values|.
|
| +void CheckAndResolveInputMethodIDs(
|
| + std::vector<std::string>* values,
|
| + const input_method::InputMethodDescriptors& supported_descriptors) {
|
| + // Extract the supported input method IDs into a set.
|
| + std::set<std::string> supported_input_method_ids;
|
| + for (size_t i = 0; i < supported_descriptors.size(); i++)
|
| + supported_input_method_ids.insert(supported_descriptors[i].id());
|
| +
|
| + // Convert engine IDs to input method extension IDs.
|
| + std::transform(values->begin(), values->end(), values->begin(),
|
| + extension_ime_util::GetInputMethodIDByEngineID);
|
| +
|
| + // Remove values that aren't found in the set of supported input method IDs.
|
| + std::vector<std::string>::iterator it = values->begin();
|
| + while (it != values->end()) {
|
| + if (it->size() && std::find(supported_input_method_ids.begin(),
|
| + supported_input_method_ids.end(),
|
| + *it) != supported_input_method_ids.end()) {
|
| + ++it;
|
| + } else {
|
| + it = values->erase(it);
|
| + }
|
| + }
|
| +}
|
| +
|
| +// Checks whether each language is supported, replacing locales with variants
|
| +// if they are available. Must be called on a thread that allows IO.
|
| +void CheckAndResolveLocales(std::string* languages) {
|
| + if (languages->empty())
|
| + return;
|
| + std::vector<std::string> values;
|
| + base::SplitString(*languages, ',', &values);
|
| +
|
| + // Remove unsupported language values and set the resolved locales.
|
| + std::vector<std::string>::iterator value_iter = values.begin();
|
| + while (value_iter != values.end()) {
|
| + std::string resolved_locale;
|
| + if (l10n_util::CheckAndResolveLocale(*value_iter, &resolved_locale)) {
|
| + *value_iter = resolved_locale;
|
| + ++value_iter;
|
| + } else {
|
| + value_iter = values.erase(value_iter);
|
| + }
|
| + }
|
| +
|
| + *languages = JoinString(values, ',');
|
| +}
|
| +
|
| +// Appends tokens from |src| that are not in |dest| to |dest|. Quadratic
|
| +// runtime; use only for small lists.
|
| +void MergeLists(std::vector<std::string>* dest,
|
| + const std::vector<std::string>& src) {
|
| + for (size_t i = 0; i < src.size(); i++) {
|
| + // Skip token if it's already in |dest|.
|
| + if (std::find(dest->begin(), dest->end(), src[i]) == dest->end())
|
| + dest->push_back(src[i]);
|
| + }
|
| +}
|
| +
|
| +// For the given input method pref, adds unique values from |synced_pref| to
|
| +// values in |pref|. The new values are converted from legacy engine IDs to
|
| +// input method IDs if necessary.
|
| +std::string AddSupportedInputMethodValues(const std::string& pref,
|
| + const std::string& synced_pref,
|
| + const char* pref_name) {
|
| + std::vector<std::string> old_tokens;
|
| + std::vector<std::string> new_tokens;
|
| + base::SplitString(pref, ',', &old_tokens);
|
| + base::SplitString(synced_pref, ',', &new_tokens);
|
| +
|
| + // Check and convert the new tokens.
|
| + if (pref_name == prefs::kLanguagePreloadEngines ||
|
| + pref_name == prefs::kLanguageEnabledExtensionImes) {
|
| + input_method::InputMethodManager* manager =
|
| + input_method::InputMethodManager::Get();
|
| + scoped_ptr<input_method::InputMethodDescriptors> supported_descriptors;
|
| +
|
| + if (pref_name == prefs::kLanguagePreloadEngines) {
|
| + // Set the known input methods.
|
| + supported_descriptors = manager->GetSupportedInputMethods();
|
| + // Add the available component extension IMEs.
|
| + ComponentExtensionIMEManager* component_extension_manager =
|
| + manager->GetComponentExtensionIMEManager();
|
| + if (component_extension_manager->IsInitialized()) {
|
| + input_method::InputMethodDescriptors component_descriptors =
|
| + component_extension_manager->GetAllIMEAsInputMethodDescriptor();
|
| + supported_descriptors->insert(supported_descriptors->end(),
|
| + component_descriptors.begin(),
|
| + component_descriptors.end());
|
| + }
|
| + } else {
|
| + supported_descriptors.reset(new input_method::InputMethodDescriptors);
|
| + manager->GetInputMethodExtensions(supported_descriptors.get());
|
| + }
|
| + CheckAndResolveInputMethodIDs(&new_tokens, *supported_descriptors);
|
| + } else if (pref_name != prefs::kLanguagePreferredLanguages) {
|
| + NOTREACHED() << "Attempting to merge an invalid preference.";
|
| + }
|
| +
|
| + // Do the actual merging.
|
| + MergeLists(&old_tokens, new_tokens);
|
| + return JoinString(old_tokens, ',');
|
| +}
|
| +
|
| +} // anonymous namespace
|
| +
|
| Preferences::Preferences()
|
| : prefs_(NULL),
|
| input_method_manager_(input_method::InputMethodManager::Get()),
|
| user_(NULL),
|
| - user_is_primary_(false) {
|
| + user_is_primary_(false),
|
| + weak_factory_(this) {
|
| // Do not observe shell, if there is no shell instance; e.g., in some unit
|
| // tests.
|
| if (ash::Shell::HasInstance())
|
| @@ -62,7 +175,8 @@ Preferences::Preferences(input_method::InputMethodManager* input_method_manager)
|
| : prefs_(NULL),
|
| input_method_manager_(input_method_manager),
|
| user_(NULL),
|
| - user_is_primary_(false) {
|
| + user_is_primary_(false),
|
| + weak_factory_(this) {
|
| // Do not observe shell, if there is no shell instance; e.g., in some unit
|
| // tests.
|
| if (ash::Shell::HasInstance())
|
| @@ -214,21 +328,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,
|
| @@ -333,9 +460,17 @@ void Preferences::InitUserPrefs(PrefServiceSyncable* prefs) {
|
| prefs, callback);
|
| touch_hud_projection_enabled_.Init(prefs::kTouchHudProjectionEnabled,
|
| prefs, callback);
|
| + preferred_languages_.Init(prefs::kLanguagePreferredLanguages,
|
| + prefs, callback);
|
| preload_engines_.Init(prefs::kLanguagePreloadEngines, prefs, callback);
|
| enabled_extension_imes_.Init(prefs::kLanguageEnabledExtensionImes,
|
| prefs, callback);
|
| + preferred_languages_syncable_.Init(prefs::kLanguagePreferredLanguagesSyncable,
|
| + prefs, callback);
|
| + preload_engines_syncable_.Init(prefs::kLanguagePreloadEnginesSyncable,
|
| + 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,
|
| @@ -516,7 +651,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);
|
| }
|
| }
|
|
|
| @@ -536,25 +673,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) {
|
| @@ -567,6 +707,10 @@ void Preferences::ApplyPreferences(ApplyReason reason,
|
| void Preferences::OnIsSyncingChanged() {
|
| DVLOG(1) << "OnIsSyncingChanged";
|
| ForceNaturalScrollDefault();
|
| + if (prefs_->GetBoolean(prefs::kLanguageShouldMergeInputMethods) &&
|
| + prefs_->IsSyncing()) {
|
| + MergeSyncedInputMethods();
|
| + }
|
| }
|
|
|
| void Preferences::ForceNaturalScrollDefault() {
|
| @@ -601,6 +745,15 @@ void Preferences::SetLanguageConfigStringListAsCSV(const char* section,
|
| }
|
| }
|
|
|
| +void Preferences::SetPreferredLanguages(scoped_ptr<std::string> languages) {
|
| + // Since this only removes locales that are unsupported on this system, we
|
| + // don't need to update the syncable prefs. If the local preference changes
|
| + // later, the sync server will lose the values we dropped, but that's okay
|
| + // since the values from this device would become the new defaults anyway.
|
| + if (*languages != preferred_languages_.GetValue())
|
| + preferred_languages_.SetValue(*languages);
|
| +}
|
| +
|
| 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
|
| @@ -626,6 +779,70 @@ 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.
|
| + 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::GetEngineIDByInputMethodID);
|
| + preload_engines_syncable_.SetValue(JoinString(engines, ','));
|
| +}
|
| +
|
| +void Preferences::MergeSyncedInputMethods() {
|
| + // This should only be done on the first ever sync.
|
| + DCHECK(prefs_->GetBoolean(prefs::kLanguageShouldMergeInputMethods));
|
| + prefs_->SetBoolean(prefs::kLanguageShouldMergeInputMethods, false);
|
| +
|
| + // Get the syncable values, because they will be overwritten once the local
|
| + // preferences are set.
|
| + std::string preferred_languages_syncable =
|
| + preferred_languages_syncable_.GetValue();
|
| + std::string preload_engines_syncable =
|
| + preload_engines_syncable_.GetValue();
|
| + std::string enabled_extension_imes_syncable =
|
| + enabled_extension_imes_syncable_.GetValue();
|
| +
|
| + // Merge the values from the sync server into the local values.
|
| + prefs_->SetString(prefs::kLanguagePreferredLanguages,
|
| + AddSupportedInputMethodValues(preferred_languages_.GetValue(),
|
| + preferred_languages_syncable,
|
| + prefs::kLanguagePreferredLanguages));
|
| + prefs_->SetString(prefs::kLanguagePreloadEngines,
|
| + AddSupportedInputMethodValues(preload_engines_.GetValue(),
|
| + preload_engines_syncable,
|
| + prefs::kLanguagePreloadEngines));
|
| + prefs_->SetString(prefs::kLanguageEnabledExtensionImes,
|
| + AddSupportedInputMethodValues(enabled_extension_imes_.GetValue(),
|
| + enabled_extension_imes_syncable,
|
| + prefs::kLanguageEnabledExtensionImes));
|
| +
|
| + // Check the new list of preferred languages to remove unsupported locales.
|
| + scoped_ptr<std::string> languages(
|
| + new std::string(preferred_languages_.GetValue()));
|
| + content::BrowserThread::PostTaskAndReply(
|
| + content::BrowserThread::FILE,
|
| + FROM_HERE,
|
| + base::Bind(&CheckAndResolveLocales, languages.get()),
|
| + base::Bind(&Preferences::SetPreferredLanguages,
|
| + weak_factory_.GetWeakPtr(),
|
| + base::Passed(&languages)));
|
| +}
|
| +
|
| void Preferences::UpdateAutoRepeatRate() {
|
| input_method::AutoRepeatRate rate;
|
| rate.initial_delay_in_ms = xkb_auto_repeat_delay_pref_.GetValue();
|
|
|