Home | History | Annotate | Download | only in chromeos
      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
    675