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

Side by Side Diff: chrome/browser/chromeos/input_method/input_method_syncer.cc

Issue 756363003: Revert of Sync starting language and input method preferences (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Created 6 years 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 unified diff | Download patch | Annotate | Revision Log
OLDNEW
(Empty)
1 // Copyright 2014 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include "chrome/browser/chromeos/input_method/input_method_syncer.h"
6
7 #include <algorithm>
8 #include <set>
9 #include <vector>
10
11 #include "base/bind.h"
12 #include "base/strings/string_split.h"
13 #include "base/strings/string_util.h"
14 #include "base/task_runner.h"
15 #include "chrome/browser/browser_process.h"
16 #include "chrome/browser/prefs/pref_service_syncable.h"
17 #include "chrome/common/pref_names.h"
18 #include "components/pref_registry/pref_registry_syncable.h"
19 #include "content/public/browser/browser_thread.h"
20 #include "ui/base/ime/chromeos/component_extension_ime_manager.h"
21 #include "ui/base/ime/chromeos/extension_ime_util.h"
22 #include "ui/base/l10n/l10n_util.h"
23
24 namespace chromeos {
25 namespace input_method {
26 namespace {
27
28 // Checks input method IDs, converting engine IDs to input method IDs and
29 // removing unsupported IDs from |values|.
30 void CheckAndResolveInputMethodIDs(
31 const input_method::InputMethodDescriptors& supported_descriptors,
32 std::vector<std::string>* values) {
33 // Extract the supported input method IDs into a set.
34 std::set<std::string> supported_input_method_ids;
35 for (const auto& descriptor : supported_descriptors)
36 supported_input_method_ids.insert(descriptor.id());
37
38 // Convert engine IDs to input method extension IDs.
39 std::transform(values->begin(), values->end(), values->begin(),
40 extension_ime_util::GetInputMethodIDByEngineID);
41
42 // Remove values that aren't found in the set of supported input method IDs.
43 std::vector<std::string>::iterator it = values->begin();
44 while (it != values->end()) {
45 if (it->size() && supported_input_method_ids.find(*it) !=
46 supported_input_method_ids.end()) {
47 ++it;
48 } else {
49 it = values->erase(it);
50 }
51 }
52 }
53
54 // Checks whether each language is supported, replacing locales with variants
55 // if they are available. Must be called on a thread that allows IO.
56 void CheckAndResolveLocales(std::string* languages) {
57 DCHECK(content::BrowserThread::GetBlockingPool()->RunsTasksOnCurrentThread());
58 if (languages->empty())
59 return;
60 std::vector<std::string> values;
61 base::SplitString(*languages, ',', &values);
62
63 const std::string app_locale = g_browser_process->GetApplicationLocale();
64
65 std::vector<std::string> accept_language_codes;
66 l10n_util::GetAcceptLanguagesForLocale(app_locale, &accept_language_codes);
67 std::sort(accept_language_codes.begin(), accept_language_codes.end());
68
69 // Remove unsupported language values.
70 std::vector<std::string>::iterator value_iter = values.begin();
71 while (value_iter != values.end()) {
72 if (binary_search(accept_language_codes.begin(),
73 accept_language_codes.end(),
74 *value_iter)) {
75 ++value_iter;
76 continue;
77 }
78
79 // If a language code resolves to a supported backup locale, replace it
80 // with the resolved locale.
81 std::string resolved_locale;
82 if (l10n_util::CheckAndResolveLocale(*value_iter, &resolved_locale)) {
83 if (binary_search(accept_language_codes.begin(),
84 accept_language_codes.end(),
85 resolved_locale)) {
86 *value_iter = resolved_locale;
87 ++value_iter;
88 continue;
89 }
90 }
91 value_iter = values.erase(value_iter);
92 }
93
94 *languages = JoinString(values, ',');
95 }
96
97 // Appends tokens from |src| that are not in |dest| to |dest|.
98 void MergeLists(std::vector<std::string>* dest,
99 const std::vector<std::string>& src) {
100 // Keep track of already-added tokens.
101 std::set<std::string> unique_tokens(dest->begin(), dest->end());
102
103 for (const std::string& token : src) {
104 // Skip token if it's already in |dest|.
105 if (binary_search(unique_tokens.begin(), unique_tokens.end(), token))
106 continue;
107 dest->push_back(token);
108 unique_tokens.insert(token);
109 }
110 }
111
112 } // anonymous namespace
113
114 InputMethodSyncer::InputMethodSyncer(
115 PrefServiceSyncable* prefs,
116 scoped_refptr<input_method::InputMethodManager::State> ime_state)
117 : prefs_(prefs),
118 ime_state_(ime_state),
119 merging_(false),
120 weak_factory_(this) {
121 }
122
123 InputMethodSyncer::~InputMethodSyncer() {
124 prefs_->RemoveObserver(this);
125 }
126
127 // static
128 void InputMethodSyncer::RegisterProfilePrefs(
129 user_prefs::PrefRegistrySyncable* registry) {
130 registry->RegisterStringPref(
131 prefs::kLanguagePreferredLanguagesSyncable,
132 "",
133 user_prefs::PrefRegistrySyncable::SYNCABLE_PREF);
134 registry->RegisterStringPref(
135 prefs::kLanguagePreloadEnginesSyncable,
136 "",
137 user_prefs::PrefRegistrySyncable::SYNCABLE_PREF);
138 registry->RegisterStringPref(
139 prefs::kLanguageEnabledExtensionImesSyncable,
140 "",
141 user_prefs::PrefRegistrySyncable::SYNCABLE_PREF);
142 registry->RegisterBooleanPref(
143 prefs::kLanguageShouldMergeInputMethods,
144 false,
145 user_prefs::PrefRegistrySyncable::UNSYNCABLE_PREF);
146 }
147
148 void InputMethodSyncer::Initialize() {
149 // This causes OnIsSyncingChanged to be called when the value of
150 // PrefService::IsSyncing() changes.
151 prefs_->AddObserver(this);
152
153 preferred_languages_syncable_.Init(prefs::kLanguagePreferredLanguagesSyncable,
154 prefs_);
155 preload_engines_syncable_.Init(prefs::kLanguagePreloadEnginesSyncable,
156 prefs_);
157 enabled_extension_imes_syncable_.Init(
158 prefs::kLanguageEnabledExtensionImesSyncable, prefs_);
159
160 BooleanPrefMember::NamedChangeCallback callback =
161 base::Bind(&InputMethodSyncer::OnPreferenceChanged,
162 base::Unretained(this));
163 preferred_languages_.Init(prefs::kLanguagePreferredLanguages,
164 prefs_, callback);
165 preload_engines_.Init(prefs::kLanguagePreloadEngines,
166 prefs_, callback);
167 enabled_extension_imes_.Init(
168 prefs::kLanguageEnabledExtensionImes, prefs_, callback);
169
170 // If we have already synced but haven't merged input methods yet, do so now.
171 if (prefs_->GetBoolean(prefs::kLanguageShouldMergeInputMethods) &&
172 !(preferred_languages_syncable_.GetValue().empty() &&
173 preload_engines_syncable_.GetValue().empty() &&
174 enabled_extension_imes_syncable_.GetValue().empty())) {
175 MergeSyncedPrefs();
176 }
177 }
178
179 void InputMethodSyncer::MergeSyncedPrefs() {
180 // This should only be done after the first ever sync.
181 DCHECK(prefs_->GetBoolean(prefs::kLanguageShouldMergeInputMethods));
182 prefs_->SetBoolean(prefs::kLanguageShouldMergeInputMethods, false);
183 merging_ = true;
184
185 std::string preferred_languages_syncable =
186 preferred_languages_syncable_.GetValue();
187 std::string preload_engines_syncable =
188 preload_engines_syncable_.GetValue();
189 std::string enabled_extension_imes_syncable =
190 enabled_extension_imes_syncable_.GetValue();
191
192 std::vector<std::string> synced_tokens;
193 std::vector<std::string> new_tokens;
194
195 // First, set the syncable prefs to the union of the local and synced prefs.
196 base::SplitString(
197 preferred_languages_syncable_.GetValue(), ',', &synced_tokens);
198 base::SplitString(preferred_languages_.GetValue(), ',', &new_tokens);
199
200 // Append the synced values to the current values.
201 MergeLists(&new_tokens, synced_tokens);
202 preferred_languages_syncable_.SetValue(JoinString(new_tokens, ','));
203
204 base::SplitString(
205 enabled_extension_imes_syncable_.GetValue(), ',', &synced_tokens);
206 base::SplitString(enabled_extension_imes_.GetValue(), ',', &new_tokens);
207
208 MergeLists(&new_tokens, synced_tokens);
209 enabled_extension_imes_syncable_.SetValue(JoinString(new_tokens, ','));
210
211 // Revert preload engines to legacy component IDs.
212 base::SplitString(preload_engines_.GetValue(), ',', &new_tokens);
213 std::transform(new_tokens.begin(), new_tokens.end(), new_tokens.begin(),
214 extension_ime_util::GetComponentIDByInputMethodID);
215 base::SplitString(
216 preload_engines_syncable_.GetValue(), ',', &synced_tokens);
217
218 MergeLists(&new_tokens, synced_tokens);
219 preload_engines_syncable_.SetValue(JoinString(new_tokens, ','));
220
221 // Second, set the local prefs, incorporating new values from the sync server.
222 preload_engines_.SetValue(
223 AddSupportedInputMethodValues(preload_engines_.GetValue(),
224 preload_engines_syncable,
225 prefs::kLanguagePreloadEngines));
226 enabled_extension_imes_.SetValue(
227 AddSupportedInputMethodValues(enabled_extension_imes_.GetValue(),
228 enabled_extension_imes_syncable,
229 prefs::kLanguageEnabledExtensionImes));
230
231 // Remove unsupported locales before updating the local languages preference.
232 scoped_ptr<std::string> languages(new std::string(
233 AddSupportedInputMethodValues(preferred_languages_.GetValue(),
234 preferred_languages_syncable,
235 prefs::kLanguagePreferredLanguages)));
236 content::BrowserThread::GetBlockingPool()->PostTaskAndReply(
237 FROM_HERE,
238 base::Bind(&CheckAndResolveLocales, languages.get()),
239 base::Bind(&InputMethodSyncer::FinishMerge,
240 weak_factory_.GetWeakPtr(),
241 base::Passed(&languages)));
242 }
243
244 std::string InputMethodSyncer::AddSupportedInputMethodValues(
245 const std::string& pref,
246 const std::string& synced_pref,
247 const char* pref_name) {
248 std::vector<std::string> old_tokens;
249 std::vector<std::string> new_tokens;
250 base::SplitString(pref, ',', &old_tokens);
251 base::SplitString(synced_pref, ',', &new_tokens);
252
253 // Check and convert the new tokens.
254 if (pref_name == prefs::kLanguagePreloadEngines ||
255 pref_name == prefs::kLanguageEnabledExtensionImes) {
256 input_method::InputMethodManager* manager =
257 input_method::InputMethodManager::Get();
258 scoped_ptr<input_method::InputMethodDescriptors> supported_descriptors;
259
260 if (pref_name == prefs::kLanguagePreloadEngines) {
261 // Set the known input methods.
262 supported_descriptors = manager->GetSupportedInputMethods();
263 // Add the available component extension IMEs.
264 ComponentExtensionIMEManager* component_extension_manager =
265 manager->GetComponentExtensionIMEManager();
266 input_method::InputMethodDescriptors component_descriptors =
267 component_extension_manager->GetAllIMEAsInputMethodDescriptor();
268 supported_descriptors->insert(supported_descriptors->end(),
269 component_descriptors.begin(),
270 component_descriptors.end());
271 } else {
272 supported_descriptors.reset(new input_method::InputMethodDescriptors);
273 ime_state_->GetInputMethodExtensions(supported_descriptors.get());
274 }
275 CheckAndResolveInputMethodIDs(*supported_descriptors, &new_tokens);
276 } else if (pref_name != prefs::kLanguagePreferredLanguages) {
277 NOTREACHED() << "Attempting to merge an invalid preference.";
278 // kLanguagePreferredLanguages is checked in CheckAndResolveLocales().
279 }
280
281 // Do the actual merging.
282 MergeLists(&old_tokens, new_tokens);
283 return JoinString(old_tokens, ',');
284 }
285
286 void InputMethodSyncer::FinishMerge(
287 scoped_ptr<std::string> languages) {
288 // Since the merge only removed locales that are unsupported on this system,
289 // we don't need to update the syncable prefs. If the local preference changes
290 // later, the sync server will lose the values we dropped. That's okay since
291 // the values from this device should then become the new defaults anyway.
292 preferred_languages_.SetValue(*languages);
293
294 // We've finished merging.
295 merging_ = false;
296 }
297
298 void InputMethodSyncer::OnPreferenceChanged(const std::string& pref_name) {
299 DCHECK(pref_name == prefs::kLanguagePreferredLanguages ||
300 pref_name == prefs::kLanguagePreloadEngines ||
301 pref_name == prefs::kLanguageEnabledExtensionImes);
302
303 if (merging_ || prefs_->GetBoolean(prefs::kLanguageShouldMergeInputMethods))
304 return;
305
306 // Set the language and input prefs at the same time. Otherwise we may,
307 // e.g., use a stale languages setting but push a new preload engines setting.
308 preferred_languages_syncable_.SetValue(preferred_languages_.GetValue());
309 enabled_extension_imes_syncable_.SetValue(enabled_extension_imes_.GetValue());
310
311 // For preload engines, use legacy xkb IDs so the preference can sync
312 // across Chrome OS and Chromium OS.
313 std::vector<std::string> engines;
314 base::SplitString(preload_engines_.GetValue(), ',', &engines);
315 std::transform(engines.begin(), engines.end(), engines.begin(),
316 extension_ime_util::GetComponentIDByInputMethodID);
317 preload_engines_syncable_.SetValue(JoinString(engines, ','));
318 }
319
320 void InputMethodSyncer::OnIsSyncingChanged() {
321 if (prefs_->GetBoolean(prefs::kLanguageShouldMergeInputMethods) &&
322 prefs_->IsSyncing()) {
323 MergeSyncedPrefs();
324 }
325 }
326
327 } // namespace input_method
328 } // namespace chromeos
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698