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