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