ea4da59255e2be36c476604553d11665a650f3f5
[platform/framework/web/crosswalk.git] / src / chrome / browser / chromeos / preferences.cc
1 // Copyright (c) 2012 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/preferences.h"
6
7 #include <vector>
8
9 #include "ash/autoclick/autoclick_controller.h"
10 #include "ash/magnifier/magnifier_constants.h"
11 #include "ash/shell.h"
12 #include "base/command_line.h"
13 #include "base/i18n/time_formatting.h"
14 #include "base/metrics/histogram.h"
15 #include "base/prefs/pref_member.h"
16 #include "base/prefs/pref_registry_simple.h"
17 #include "base/prefs/scoped_user_pref_update.h"
18 #include "base/strings/string_split.h"
19 #include "base/strings/string_util.h"
20 #include "base/strings/utf_string_conversions.h"
21 #include "base/sys_info.h"
22 #include "chrome/browser/browser_process.h"
23 #include "chrome/browser/chrome_notification_types.h"
24 #include "chrome/browser/chromeos/accessibility/magnification_manager.h"
25 #include "chrome/browser/chromeos/drive/file_system_util.h"
26 #include "chrome/browser/chromeos/input_method/input_method_util.h"
27 #include "chrome/browser/chromeos/login/login_utils.h"
28 #include "chrome/browser/chromeos/login/user.h"
29 #include "chrome/browser/chromeos/system/input_device_settings.h"
30 #include "chrome/browser/download/download_prefs.h"
31 #include "chrome/browser/feedback/tracing_manager.h"
32 #include "chrome/browser/prefs/pref_service_syncable.h"
33 #include "chrome/common/chrome_switches.h"
34 #include "chrome/common/pref_names.h"
35 #include "chromeos/chromeos_switches.h"
36 #include "chromeos/ime/input_method_manager.h"
37 #include "chromeos/ime/xkeyboard.h"
38 #include "chromeos/system/statistics_provider.h"
39 #include "components/user_prefs/pref_registry_syncable.h"
40 #include "third_party/icu/source/i18n/unicode/timezone.h"
41 #include "ui/events/event_constants.h"
42 #include "ui/events/event_utils.h"
43 #include "url/gurl.h"
44
45 namespace chromeos {
46
47 static const char kFallbackInputMethodLocale[] = "en-US";
48
49 Preferences::Preferences()
50     : prefs_(NULL),
51       input_method_manager_(input_method::InputMethodManager::Get()),
52       user_(NULL),
53       user_is_primary_(false) {
54   // Do not observe shell, if there is no shell instance; e.g., in some unit
55   // tests.
56   if (ash::Shell::HasInstance())
57     ash::Shell::GetInstance()->AddShellObserver(this);
58 }
59
60 Preferences::Preferences(input_method::InputMethodManager* input_method_manager)
61     : prefs_(NULL),
62       input_method_manager_(input_method_manager),
63       user_(NULL) {
64   // Do not observe shell, if there is no shell instance; e.g., in some unit
65   // tests.
66   if (ash::Shell::HasInstance())
67     ash::Shell::GetInstance()->AddShellObserver(this);
68 }
69
70 Preferences::~Preferences() {
71   prefs_->RemoveObserver(this);
72   UserManager::Get()->RemoveSessionStateObserver(this);
73   // If shell instance is destoryed before this preferences instance, there is
74   // no need to remove this shell observer.
75   if (ash::Shell::HasInstance())
76     ash::Shell::GetInstance()->RemoveShellObserver(this);
77 }
78
79 // static
80 void Preferences::RegisterPrefs(PrefRegistrySimple* registry) {
81   registry->RegisterBooleanPref(prefs::kOwnerPrimaryMouseButtonRight, false);
82   registry->RegisterBooleanPref(prefs::kOwnerTapToClickEnabled, true);
83   registry->RegisterBooleanPref(prefs::kVirtualKeyboardEnabled, false);
84 }
85
86 // static
87 void Preferences::RegisterProfilePrefs(
88     user_prefs::PrefRegistrySyncable* registry) {
89   std::string hardware_keyboard_id;
90   // TODO(yusukes): Remove the runtime hack.
91   if (base::SysInfo::IsRunningOnChromeOS()) {
92     DCHECK(g_browser_process);
93     PrefService* local_state = g_browser_process->local_state();
94     DCHECK(local_state);
95     hardware_keyboard_id =
96         local_state->GetString(prefs::kHardwareKeyboardLayout);
97   } else {
98     hardware_keyboard_id = "xkb:us::eng";  // only for testing.
99   }
100
101   registry->RegisterBooleanPref(
102       prefs::kPerformanceTracingEnabled,
103       false,
104       user_prefs::PrefRegistrySyncable::UNSYNCABLE_PREF);
105
106   registry->RegisterBooleanPref(
107       prefs::kTapToClickEnabled,
108       true,
109       user_prefs::PrefRegistrySyncable::SYNCABLE_PRIORITY_PREF);
110   registry->RegisterBooleanPref(
111       prefs::kTapDraggingEnabled,
112       false,
113       user_prefs::PrefRegistrySyncable::SYNCABLE_PRIORITY_PREF);
114   registry->RegisterBooleanPref(
115       prefs::kEnableTouchpadThreeFingerClick,
116       false,
117       user_prefs::PrefRegistrySyncable::UNSYNCABLE_PREF);
118   registry->RegisterBooleanPref(
119       prefs::kNaturalScroll,
120       CommandLine::ForCurrentProcess()->HasSwitch(
121           switches::kNaturalScrollDefault),
122       user_prefs::PrefRegistrySyncable::SYNCABLE_PRIORITY_PREF);
123   registry->RegisterBooleanPref(
124       prefs::kPrimaryMouseButtonRight,
125       false,
126       user_prefs::PrefRegistrySyncable::SYNCABLE_PRIORITY_PREF);
127   registry->RegisterBooleanPref(
128       prefs::kLabsMediaplayerEnabled,
129       false,
130       user_prefs::PrefRegistrySyncable::UNSYNCABLE_PREF);
131   registry->RegisterBooleanPref(
132       prefs::kLabsAdvancedFilesystemEnabled,
133       false,
134       user_prefs::PrefRegistrySyncable::UNSYNCABLE_PREF);
135   registry->RegisterBooleanPref(
136       prefs::kStickyKeysEnabled,
137       false,
138       user_prefs::PrefRegistrySyncable::SYNCABLE_PREF);
139   registry->RegisterBooleanPref(
140       prefs::kLargeCursorEnabled,
141       false,
142       user_prefs::PrefRegistrySyncable::SYNCABLE_PREF);
143   registry->RegisterBooleanPref(
144       prefs::kSpokenFeedbackEnabled,
145       false,
146       user_prefs::PrefRegistrySyncable::UNSYNCABLE_PREF);
147   registry->RegisterBooleanPref(
148       prefs::kHighContrastEnabled,
149       false,
150       user_prefs::PrefRegistrySyncable::SYNCABLE_PREF);
151   registry->RegisterBooleanPref(
152       prefs::kScreenMagnifierEnabled,
153       false,
154       user_prefs::PrefRegistrySyncable::SYNCABLE_PREF);
155   registry->RegisterIntegerPref(
156       prefs::kScreenMagnifierType,
157       ash::kDefaultMagnifierType,
158       user_prefs::PrefRegistrySyncable::SYNCABLE_PREF);
159   registry->RegisterDoublePref(
160       prefs::kScreenMagnifierScale,
161       std::numeric_limits<double>::min(),
162       user_prefs::PrefRegistrySyncable::UNSYNCABLE_PREF);
163   registry->RegisterBooleanPref(
164       prefs::kAutoclickEnabled,
165       false,
166       user_prefs::PrefRegistrySyncable::SYNCABLE_PREF);
167   registry->RegisterIntegerPref(
168       prefs::kAutoclickDelayMs,
169       ash::AutoclickController::kDefaultAutoclickDelayMs,
170       user_prefs::PrefRegistrySyncable::SYNCABLE_PREF);
171   registry->RegisterBooleanPref(
172     prefs::kVirtualKeyboardEnabled,
173     false,
174     user_prefs::PrefRegistrySyncable::SYNCABLE_PREF);
175   registry->RegisterBooleanPref(
176       prefs::kShouldAlwaysShowAccessibilityMenu,
177       false,
178       user_prefs::PrefRegistrySyncable::SYNCABLE_PREF);
179   registry->RegisterIntegerPref(
180       prefs::kMouseSensitivity,
181       3,
182       user_prefs::PrefRegistrySyncable::SYNCABLE_PRIORITY_PREF);
183   registry->RegisterIntegerPref(
184       prefs::kTouchpadSensitivity,
185       3,
186       user_prefs::PrefRegistrySyncable::SYNCABLE_PRIORITY_PREF);
187   registry->RegisterBooleanPref(
188       prefs::kUse24HourClock,
189       base::GetHourClockType() == base::k24HourClock,
190       user_prefs::PrefRegistrySyncable::SYNCABLE_PREF);
191   registry->RegisterBooleanPref(
192       prefs::kDisableDrive,
193       false,
194       user_prefs::PrefRegistrySyncable::SYNCABLE_PREF);
195   registry->RegisterBooleanPref(
196       prefs::kDisableDriveOverCellular,
197       true,
198       user_prefs::PrefRegistrySyncable::SYNCABLE_PREF);
199   registry->RegisterBooleanPref(
200       prefs::kDisableDriveHostedFiles,
201       false,
202       user_prefs::PrefRegistrySyncable::SYNCABLE_PREF);
203   // We don't sync prefs::kLanguageCurrentInputMethod and PreviousInputMethod
204   // because they're just used to track the logout state of the device.
205   registry->RegisterStringPref(
206       prefs::kLanguageCurrentInputMethod,
207       "",
208       user_prefs::PrefRegistrySyncable::UNSYNCABLE_PREF);
209   registry->RegisterStringPref(
210       prefs::kLanguagePreviousInputMethod,
211       "",
212       user_prefs::PrefRegistrySyncable::UNSYNCABLE_PREF);
213   // We don't sync the list of input methods and preferred languages since a
214   // user might use two or more devices with different hardware keyboards.
215   // crosbug.com/15181
216   registry->RegisterStringPref(
217       prefs::kLanguagePreferredLanguages,
218       kFallbackInputMethodLocale,
219       user_prefs::PrefRegistrySyncable::UNSYNCABLE_PREF);
220   registry->RegisterStringPref(
221       prefs::kLanguagePreloadEngines,
222       hardware_keyboard_id,
223       user_prefs::PrefRegistrySyncable::UNSYNCABLE_PREF);
224   registry->RegisterStringPref(
225       prefs::kLanguageEnabledExtensionImes,
226       "",
227       user_prefs::PrefRegistrySyncable::UNSYNCABLE_PREF);
228
229   registry->RegisterIntegerPref(
230       prefs::kLanguageRemapSearchKeyTo,
231       input_method::kSearchKey,
232       user_prefs::PrefRegistrySyncable::SYNCABLE_PRIORITY_PREF);
233   registry->RegisterIntegerPref(
234       prefs::kLanguageRemapControlKeyTo,
235       input_method::kControlKey,
236       user_prefs::PrefRegistrySyncable::SYNCABLE_PRIORITY_PREF);
237   registry->RegisterIntegerPref(
238       prefs::kLanguageRemapAltKeyTo,
239       input_method::kAltKey,
240       user_prefs::PrefRegistrySyncable::SYNCABLE_PRIORITY_PREF);
241   // We don't sync the CapsLock remapping pref, since the UI hides this pref
242   // on certain devices, so syncing a non-default value to a device that
243   // doesn't allow changing the pref would be odd. http://crbug.com/167237
244   registry->RegisterIntegerPref(
245       prefs::kLanguageRemapCapsLockKeyTo,
246       input_method::kCapsLockKey,
247       user_prefs::PrefRegistrySyncable::UNSYNCABLE_PREF);
248   registry->RegisterIntegerPref(
249       prefs::kLanguageRemapDiamondKeyTo,
250       input_method::kControlKey,
251       user_prefs::PrefRegistrySyncable::SYNCABLE_PRIORITY_PREF);
252   // The following pref isn't synced since the user may desire a different value
253   // depending on whether an external keyboard is attached to a particular
254   // device.
255   registry->RegisterBooleanPref(
256       prefs::kLanguageSendFunctionKeys,
257       false,
258       user_prefs::PrefRegistrySyncable::UNSYNCABLE_PREF);
259   // We don't sync the following keyboard prefs since they are not user-
260   // configurable.
261   registry->RegisterBooleanPref(
262       prefs::kLanguageXkbAutoRepeatEnabled,
263       true,
264       user_prefs::PrefRegistrySyncable::UNSYNCABLE_PREF);
265   registry->RegisterIntegerPref(
266       prefs::kLanguageXkbAutoRepeatDelay,
267       language_prefs::kXkbAutoRepeatDelayInMs,
268       user_prefs::PrefRegistrySyncable::UNSYNCABLE_PREF);
269   registry->RegisterIntegerPref(
270       prefs::kLanguageXkbAutoRepeatInterval,
271       language_prefs::kXkbAutoRepeatIntervalInMs,
272       user_prefs::PrefRegistrySyncable::UNSYNCABLE_PREF);
273
274   // Mobile plan notifications default to on.
275   registry->RegisterBooleanPref(
276       prefs::kShowPlanNotifications,
277       true,
278       user_prefs::PrefRegistrySyncable::SYNCABLE_PREF);
279
280   // 3G first-time usage promo will be shown at least once.
281   registry->RegisterBooleanPref(
282       prefs::kShow3gPromoNotification,
283       true,
284       user_prefs::PrefRegistrySyncable::UNSYNCABLE_PREF);
285
286   // Initially all existing users would see "What's new" for current version
287   // after update.
288   registry->RegisterStringPref(prefs::kChromeOSReleaseNotesVersion,
289                                "0.0.0.0",
290                                user_prefs::PrefRegistrySyncable::SYNCABLE_PREF);
291
292   registry->RegisterBooleanPref(
293       prefs::kExternalStorageDisabled,
294       false,
295       user_prefs::PrefRegistrySyncable::UNSYNCABLE_PREF);
296
297   registry->RegisterStringPref(
298       prefs::kTermsOfServiceURL,
299       "",
300       user_prefs::PrefRegistrySyncable::UNSYNCABLE_PREF);
301
302   registry->RegisterBooleanPref(
303       prefs::kTouchHudProjectionEnabled,
304       false,
305       user_prefs::PrefRegistrySyncable::UNSYNCABLE_PREF);
306 }
307
308 void Preferences::InitUserPrefs(PrefServiceSyncable* prefs) {
309   prefs_ = prefs;
310
311   BooleanPrefMember::NamedChangeCallback callback =
312       base::Bind(&Preferences::OnPreferenceChanged, base::Unretained(this));
313
314   performance_tracing_enabled_.Init(prefs::kPerformanceTracingEnabled,
315                                     prefs, callback);
316   tap_to_click_enabled_.Init(prefs::kTapToClickEnabled, prefs, callback);
317   tap_dragging_enabled_.Init(prefs::kTapDraggingEnabled, prefs, callback);
318   three_finger_click_enabled_.Init(prefs::kEnableTouchpadThreeFingerClick,
319       prefs, callback);
320   natural_scroll_.Init(prefs::kNaturalScroll, prefs, callback);
321   mouse_sensitivity_.Init(prefs::kMouseSensitivity, prefs, callback);
322   touchpad_sensitivity_.Init(prefs::kTouchpadSensitivity, prefs, callback);
323   primary_mouse_button_right_.Init(prefs::kPrimaryMouseButtonRight,
324                                    prefs, callback);
325   download_default_directory_.Init(prefs::kDownloadDefaultDirectory,
326                                    prefs, callback);
327   touch_hud_projection_enabled_.Init(prefs::kTouchHudProjectionEnabled,
328                                      prefs, callback);
329   preload_engines_.Init(prefs::kLanguagePreloadEngines, prefs, callback);
330   enabled_extension_imes_.Init(prefs::kLanguageEnabledExtensionImes,
331                                prefs, callback);
332   current_input_method_.Init(prefs::kLanguageCurrentInputMethod,
333                              prefs, callback);
334   previous_input_method_.Init(prefs::kLanguagePreviousInputMethod,
335                               prefs, callback);
336
337   xkb_auto_repeat_enabled_.Init(
338       prefs::kLanguageXkbAutoRepeatEnabled, prefs, callback);
339   xkb_auto_repeat_delay_pref_.Init(
340       prefs::kLanguageXkbAutoRepeatDelay, prefs, callback);
341   xkb_auto_repeat_interval_pref_.Init(
342       prefs::kLanguageXkbAutoRepeatInterval, prefs, callback);
343 }
344
345 void Preferences::Init(PrefServiceSyncable* prefs, const User* user) {
346   DCHECK(user);
347   user_ = user;
348   user_is_primary_ = UserManager::Get()->GetPrimaryUser() == user_;
349   InitUserPrefs(prefs);
350
351   UserManager::Get()->AddSessionStateObserver(this);
352
353   // This causes OnIsSyncingChanged to be called when the value of
354   // PrefService::IsSyncing() changes.
355   prefs->AddObserver(this);
356
357   // Initialize preferences to currently saved state.
358   ApplyPreferences(REASON_INITIALIZATION, "");
359
360   // If a guest is logged in, initialize the prefs as if this is the first
361   // login.
362   if (CommandLine::ForCurrentProcess()->HasSwitch(switches::kGuestSession)) {
363     LoginUtils::Get()->SetFirstLoginPrefs(prefs);
364   }
365 }
366
367 void Preferences::InitUserPrefsForTesting(PrefServiceSyncable* prefs,
368                                           const User* user) {
369   user_ = user;
370   InitUserPrefs(prefs);
371 }
372
373 void Preferences::SetInputMethodListForTesting() {
374   SetInputMethodList();
375 }
376
377 void Preferences::OnPreferenceChanged(const std::string& pref_name) {
378   ApplyPreferences(REASON_PREF_CHANGED, pref_name);
379 }
380
381 void Preferences::ApplyPreferences(ApplyReason reason,
382                                    const std::string& pref_name) {
383   DCHECK(reason != REASON_PREF_CHANGED || !pref_name.empty());
384   const bool user_is_owner =
385       UserManager::Get()->GetOwnerEmail() == user_->email();
386   const bool user_is_active = user_->is_active();
387
388   system::TouchpadSettings touchpad_settings;
389   system::MouseSettings mouse_settings;
390
391   if (user_is_primary_ && (reason == REASON_INITIALIZATION ||
392                            pref_name == prefs::kPerformanceTracingEnabled)) {
393     const bool enabled = performance_tracing_enabled_.GetValue();
394     if (enabled)
395       tracing_manager_ = TracingManager::Create();
396     else
397       tracing_manager_.reset();
398   }
399   if (reason != REASON_PREF_CHANGED || pref_name == prefs::kTapToClickEnabled) {
400     const bool enabled = tap_to_click_enabled_.GetValue();
401     if (user_is_active)
402       touchpad_settings.SetTapToClick(enabled);
403     if (reason == REASON_PREF_CHANGED)
404       UMA_HISTOGRAM_BOOLEAN("Touchpad.TapToClick.Changed", enabled);
405     else if (reason == REASON_INITIALIZATION)
406       UMA_HISTOGRAM_BOOLEAN("Touchpad.TapToClick.Started", enabled);
407
408     // Save owner preference in local state to use on login screen.
409     if (user_is_owner) {
410       PrefService* prefs = g_browser_process->local_state();
411       if (prefs->GetBoolean(prefs::kOwnerTapToClickEnabled) != enabled)
412         prefs->SetBoolean(prefs::kOwnerTapToClickEnabled, enabled);
413     }
414   }
415   if (reason != REASON_PREF_CHANGED ||
416       pref_name == prefs::kTapDraggingEnabled) {
417     const bool enabled = tap_dragging_enabled_.GetValue();
418     if (user_is_active)
419       touchpad_settings.SetTapDragging(enabled);
420     if (reason == REASON_PREF_CHANGED)
421       UMA_HISTOGRAM_BOOLEAN("Touchpad.TapDragging.Changed", enabled);
422     else if (reason == REASON_INITIALIZATION)
423       UMA_HISTOGRAM_BOOLEAN("Touchpad.TapDragging.Started", enabled);
424   }
425   if (reason != REASON_PREF_CHANGED ||
426       pref_name == prefs::kEnableTouchpadThreeFingerClick) {
427     const bool enabled = three_finger_click_enabled_.GetValue();
428     if (user_is_active)
429       touchpad_settings.SetThreeFingerClick(enabled);
430     if (reason == REASON_PREF_CHANGED)
431       UMA_HISTOGRAM_BOOLEAN("Touchpad.ThreeFingerClick.Changed", enabled);
432     else if (reason == REASON_INITIALIZATION)
433       UMA_HISTOGRAM_BOOLEAN("Touchpad.ThreeFingerClick.Started", enabled);
434   }
435   if (reason != REASON_PREF_CHANGED || pref_name == prefs::kNaturalScroll) {
436     // Force natural scroll default if we've sync'd and if the cmd line arg is
437     // set.
438     ForceNaturalScrollDefault();
439
440     const bool enabled = natural_scroll_.GetValue();
441     DVLOG(1) << "Natural scroll set to " << enabled;
442     if (user_is_active)
443       ui::SetNaturalScroll(enabled);
444     if (reason == REASON_PREF_CHANGED)
445       UMA_HISTOGRAM_BOOLEAN("Touchpad.NaturalScroll.Changed", enabled);
446     else if (reason == REASON_INITIALIZATION)
447       UMA_HISTOGRAM_BOOLEAN("Touchpad.NaturalScroll.Started", enabled);
448   }
449   if (reason != REASON_PREF_CHANGED || pref_name == prefs::kMouseSensitivity) {
450     const int sensitivity = mouse_sensitivity_.GetValue();
451     if (user_is_active)
452       mouse_settings.SetSensitivity(sensitivity);
453     if (reason == REASON_PREF_CHANGED) {
454       UMA_HISTOGRAM_ENUMERATION("Mouse.PointerSensitivity.Changed",
455                                 sensitivity,
456                                 system::kMaxPointerSensitivity + 1);
457     } else if (reason == REASON_INITIALIZATION) {
458       UMA_HISTOGRAM_ENUMERATION("Mouse.PointerSensitivity.Started",
459                                 sensitivity,
460                                 system::kMaxPointerSensitivity + 1);
461     }
462   }
463   if (reason != REASON_PREF_CHANGED ||
464       pref_name == prefs::kTouchpadSensitivity) {
465     const int sensitivity = touchpad_sensitivity_.GetValue();
466     if (user_is_active)
467       touchpad_settings.SetSensitivity(sensitivity);
468     if (reason == REASON_PREF_CHANGED) {
469       UMA_HISTOGRAM_ENUMERATION("Touchpad.PointerSensitivity.Changed",
470                                 sensitivity,
471                                 system::kMaxPointerSensitivity + 1);
472     } else if (reason == REASON_INITIALIZATION) {
473       UMA_HISTOGRAM_ENUMERATION("Touchpad.PointerSensitivity.Started",
474                                 sensitivity,
475                                 system::kMaxPointerSensitivity + 1);
476     }
477   }
478   if (reason != REASON_PREF_CHANGED ||
479       pref_name == prefs::kPrimaryMouseButtonRight) {
480     const bool right = primary_mouse_button_right_.GetValue();
481     if (user_is_active)
482       mouse_settings.SetPrimaryButtonRight(right);
483     if (reason == REASON_PREF_CHANGED)
484       UMA_HISTOGRAM_BOOLEAN("Mouse.PrimaryButtonRight.Changed", right);
485     else if (reason == REASON_INITIALIZATION)
486       UMA_HISTOGRAM_BOOLEAN("Mouse.PrimaryButtonRight.Started", right);
487     // Save owner preference in local state to use on login screen.
488     if (user_is_owner) {
489       PrefService* prefs = g_browser_process->local_state();
490       if (prefs->GetBoolean(prefs::kOwnerPrimaryMouseButtonRight) != right)
491         prefs->SetBoolean(prefs::kOwnerPrimaryMouseButtonRight, right);
492     }
493   }
494   if (reason != REASON_PREF_CHANGED ||
495       pref_name == prefs::kDownloadDefaultDirectory) {
496     const bool default_download_to_drive = drive::util::IsUnderDriveMountPoint(
497         download_default_directory_.GetValue());
498     if (reason == REASON_PREF_CHANGED)
499       UMA_HISTOGRAM_BOOLEAN(
500           "FileBrowser.DownloadDestination.IsGoogleDrive.Changed",
501           default_download_to_drive);
502     else if (reason == REASON_INITIALIZATION)
503       UMA_HISTOGRAM_BOOLEAN(
504           "FileBrowser.DownloadDestination.IsGoogleDrive.Started",
505           default_download_to_drive);
506   }
507   if (reason != REASON_PREF_CHANGED ||
508       pref_name == prefs::kTouchHudProjectionEnabled) {
509     if (user_is_active) {
510       const bool enabled = touch_hud_projection_enabled_.GetValue();
511       ash::Shell::GetInstance()->SetTouchHudProjectionEnabled(enabled);
512     }
513   }
514
515   if (reason != REASON_PREF_CHANGED ||
516       pref_name == prefs::kLanguageXkbAutoRepeatEnabled) {
517     if (user_is_active) {
518       const bool enabled = xkb_auto_repeat_enabled_.GetValue();
519       input_method::InputMethodManager::Get()->GetXKeyboard()
520           ->SetAutoRepeatEnabled(enabled);
521     }
522   }
523   if (reason != REASON_PREF_CHANGED ||
524       pref_name == prefs::kLanguageXkbAutoRepeatDelay ||
525       pref_name == prefs::kLanguageXkbAutoRepeatInterval) {
526     if (user_is_active)
527       UpdateAutoRepeatRate();
528   }
529
530   if (reason != REASON_PREF_CHANGED && user_is_active) {
531     SetInputMethodList();
532   } else if (pref_name == prefs::kLanguagePreloadEngines && user_is_active) {
533     SetLanguageConfigStringListAsCSV(language_prefs::kGeneralSectionName,
534                                      language_prefs::kPreloadEnginesConfigName,
535                                      preload_engines_.GetValue());
536   }
537
538   if (reason != REASON_PREF_CHANGED ||
539       pref_name == prefs::kLanguageEnabledExtensionImes) {
540     if (user_is_active) {
541       std::string value(enabled_extension_imes_.GetValue());
542
543       std::vector<std::string> split_values;
544       if (!value.empty())
545         base::SplitString(value, ',', &split_values);
546
547       input_method_manager_->SetEnabledExtensionImes(&split_values);
548     }
549   }
550
551   if (user_is_active) {
552     system::InputDeviceSettings::Get()->UpdateTouchpadSettings(
553         touchpad_settings);
554     system::InputDeviceSettings::Get()->UpdateMouseSettings(mouse_settings);
555   }
556 }
557
558 void Preferences::OnIsSyncingChanged() {
559   DVLOG(1) << "OnIsSyncingChanged";
560   ForceNaturalScrollDefault();
561 }
562
563 void Preferences::ForceNaturalScrollDefault() {
564   DVLOG(1) << "ForceNaturalScrollDefault";
565   if (CommandLine::ForCurrentProcess()->HasSwitch(
566           switches::kNaturalScrollDefault) &&
567       prefs_->IsSyncing() &&
568       !prefs_->GetUserPrefValue(prefs::kNaturalScroll)) {
569     DVLOG(1) << "Natural scroll forced to true";
570     natural_scroll_.SetValue(true);
571     UMA_HISTOGRAM_BOOLEAN("Touchpad.NaturalScroll.Forced", true);
572   }
573 }
574
575 void Preferences::SetLanguageConfigStringListAsCSV(const char* section,
576                                                    const char* name,
577                                                    const std::string& value) {
578   VLOG(1) << "Setting " << name << " to '" << value << "'";
579
580   std::vector<std::string> split_values;
581   if (!value.empty())
582     base::SplitString(value, ',', &split_values);
583
584   if (section == std::string(language_prefs::kGeneralSectionName) &&
585       name == std::string(language_prefs::kPreloadEnginesConfigName)) {
586     input_method_manager_->ReplaceEnabledInputMethods(split_values);
587     return;
588   }
589 }
590
591 void Preferences::SetInputMethodList() {
592   // When |preload_engines_| are set, InputMethodManager::ChangeInputMethod()
593   // might be called to change the current input method to the first one in the
594   // |preload_engines_| list. This also updates previous/current input method
595   // prefs. That's why GetValue() calls are placed before the
596   // SetLanguageConfigStringListAsCSV() call below.
597   const std::string previous_input_method_id =
598       previous_input_method_.GetValue();
599   const std::string current_input_method_id = current_input_method_.GetValue();
600   SetLanguageConfigStringListAsCSV(language_prefs::kGeneralSectionName,
601                                    language_prefs::kPreloadEnginesConfigName,
602                                    preload_engines_.GetValue());
603
604   // ChangeInputMethod() has to be called AFTER the value of |preload_engines_|
605   // is sent to the InputMethodManager. Otherwise, the ChangeInputMethod request
606   // might be ignored as an invalid input method ID. The ChangeInputMethod()
607   // calls are also necessary to restore the previous/current input method prefs
608   // which could have been modified by the SetLanguageConfigStringListAsCSV call
609   // above to the original state.
610   if (!previous_input_method_id.empty())
611     input_method_manager_->ChangeInputMethod(previous_input_method_id);
612   if (!current_input_method_id.empty())
613     input_method_manager_->ChangeInputMethod(current_input_method_id);
614 }
615
616 void Preferences::UpdateAutoRepeatRate() {
617   input_method::AutoRepeatRate rate;
618   rate.initial_delay_in_ms = xkb_auto_repeat_delay_pref_.GetValue();
619   rate.repeat_interval_in_ms = xkb_auto_repeat_interval_pref_.GetValue();
620   DCHECK(rate.initial_delay_in_ms > 0);
621   DCHECK(rate.repeat_interval_in_ms > 0);
622   input_method::InputMethodManager::Get()->GetXKeyboard()
623       ->SetAutoRepeatRate(rate);
624 }
625
626 void Preferences::OnTouchHudProjectionToggled(bool enabled) {
627   if (touch_hud_projection_enabled_.GetValue() == enabled)
628     return;
629   if (!user_->is_active())
630     return;
631   touch_hud_projection_enabled_.SetValue(enabled);
632 }
633
634 void Preferences::ActiveUserChanged(const User* active_user) {
635   if (active_user != user_)
636     return;
637   ApplyPreferences(REASON_ACTIVE_USER_CHANGED, "");
638 }
639
640 }  // namespace chromeos