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