Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(2739)

Unified Diff: chrome/browser/chromeos/preferences.cc

Issue 312023002: Sync starting language and input method preferences (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Created 6 years, 5 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
Index: chrome/browser/chromeos/preferences.cc
diff --git a/chrome/browser/chromeos/preferences.cc b/chrome/browser/chromeos/preferences.cc
index 1a792e0206025446cb4d1d8b25e29ea1fc4dbe42..886acf4819daf54e62630ffdde30c63a1d27fe62 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,26 +32,139 @@
#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"
#include "chromeos/system/statistics_provider.h"
#include "components/feedback/tracing_manager.h"
#include "components/pref_registry/pref_registry_syncable.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,
@@ -335,9 +462,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,
@@ -517,7 +652,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);
}
}
@@ -537,25 +674,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) {
@@ -568,6 +708,10 @@ void Preferences::ApplyPreferences(ApplyReason reason,
void Preferences::OnIsSyncingChanged() {
DVLOG(1) << "OnIsSyncingChanged";
ForceNaturalScrollDefault();
+ if (prefs_->GetBoolean(prefs::kLanguageShouldMergeInputMethods) &&
+ prefs_->IsSyncing()) {
+ MergeSyncedInputMethods();
+ }
}
void Preferences::ForceNaturalScrollDefault() {
@@ -602,6 +746,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
@@ -627,6 +780,68 @@ 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);
+
+ // Merge the values from the sync server into the local values.
+ preferred_languages_.SetValue(
dzhioev (left Google) 2014/07/24 20:31:34 I can't understand why do you set preferred langua
michaelpg 2014/07/25 23:49:08 The check is asynchronous. So this way, the change
dzhioev (left Google) 2014/08/01 15:30:41 I understand part about checking. But still I don'
+ AddSupportedInputMethodValues(preferred_languages_.GetValue(),
+ preferred_languages_syncable_.GetValue(),
+ prefs::kLanguagePreferredLanguages));
+ preload_engines_.SetValue(
+ AddSupportedInputMethodValues(preload_engines_.GetValue(),
+ preload_engines_syncable_.GetValue(),
+ prefs::kLanguagePreloadEngines));
+ enabled_extension_imes_.SetValue(
dzhioev (left Google) 2014/07/24 20:31:34 I think the better idea is to set prefs directly t
michaelpg 2014/07/25 23:49:08 Does this look better? When any of these prefs ar
dzhioev (left Google) 2014/08/01 15:30:41 Yes, it's better.
+ AddSupportedInputMethodValues(enabled_extension_imes_.GetValue(),
+ enabled_extension_imes_syncable_.GetValue(),
+ prefs::kLanguageEnabledExtensionImes));
+
+ // Apply the new values.
+ SetLanguageConfigStringListAsCSV(language_prefs::kGeneralSectionName,
+ language_prefs::kPreloadEnginesConfigName,
+ preload_engines_.GetValue());
+ SetEnabledExtensionImes();
+ SetSyncableInputMethodPrefs();
+
+ // 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();

Powered by Google App Engine
This is Rietveld 408576698