preferences.cc revision 3551c9c881056c480085172ff9840cab31610854
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/base/events/event_constants.h"
39#include "ui/base/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_PRIORITY_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_PRIORITY_PREF);
149  registry->RegisterBooleanPref(
150      prefs::kScreenMagnifierEnabled,
151      false,
152      user_prefs::PrefRegistrySyncable::SYNCABLE_PRIORITY_PREF);
153  registry->RegisterIntegerPref(
154      prefs::kScreenMagnifierType,
155      ash::kDefaultMagnifierType,
156      user_prefs::PrefRegistrySyncable::SYNCABLE_PRIORITY_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_PRIORITY_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  for (size_t i = 0; i < language_prefs::kNumChewingBooleanPrefs; ++i) {
215    registry->RegisterBooleanPref(
216        language_prefs::kChewingBooleanPrefs[i].pref_name,
217        language_prefs::kChewingBooleanPrefs[i].default_pref_value,
218        language_prefs::kChewingBooleanPrefs[i].sync_status);
219  }
220  for (size_t i = 0; i < language_prefs::kNumChewingMultipleChoicePrefs; ++i) {
221    registry->RegisterStringPref(
222        language_prefs::kChewingMultipleChoicePrefs[i].pref_name,
223        language_prefs::kChewingMultipleChoicePrefs[i].default_pref_value,
224        language_prefs::kChewingMultipleChoicePrefs[i].sync_status);
225  }
226  registry->RegisterIntegerPref(
227      language_prefs::kChewingHsuSelKeyType.pref_name,
228      language_prefs::kChewingHsuSelKeyType.default_pref_value,
229      language_prefs::kChewingHsuSelKeyType.sync_status);
230
231  for (size_t i = 0; i < language_prefs::kNumChewingIntegerPrefs; ++i) {
232    registry->RegisterIntegerPref(
233        language_prefs::kChewingIntegerPrefs[i].pref_name,
234        language_prefs::kChewingIntegerPrefs[i].default_pref_value,
235        language_prefs::kChewingIntegerPrefs[i].sync_status);
236  }
237  registry->RegisterStringPref(
238      prefs::kLanguageHangulKeyboard,
239      language_prefs::kHangulKeyboardNameIDPairs[0].keyboard_id,
240      user_prefs::PrefRegistrySyncable::SYNCABLE_PRIORITY_PREF);
241  registry->RegisterStringPref(
242      prefs::kLanguageHangulHanjaBindingKeys,
243      language_prefs::kHangulHanjaBindingKeys,
244      // Don't sync the pref as it's not user-configurable
245      user_prefs::PrefRegistrySyncable::UNSYNCABLE_PREF);
246  for (size_t i = 0; i < language_prefs::kNumPinyinBooleanPrefs; ++i) {
247    registry->RegisterBooleanPref(
248        language_prefs::kPinyinBooleanPrefs[i].pref_name,
249        language_prefs::kPinyinBooleanPrefs[i].default_pref_value,
250        language_prefs::kPinyinBooleanPrefs[i].sync_status);
251  }
252  for (size_t i = 0; i < language_prefs::kNumPinyinIntegerPrefs; ++i) {
253    registry->RegisterIntegerPref(
254        language_prefs::kPinyinIntegerPrefs[i].pref_name,
255        language_prefs::kPinyinIntegerPrefs[i].default_pref_value,
256        language_prefs::kPinyinIntegerPrefs[i].sync_status);
257  }
258  registry->RegisterIntegerPref(
259      language_prefs::kPinyinDoublePinyinSchema.pref_name,
260      language_prefs::kPinyinDoublePinyinSchema.default_pref_value,
261      user_prefs::PrefRegistrySyncable::UNSYNCABLE_PREF);
262
263  for (size_t i = 0; i < language_prefs::kNumMozcBooleanPrefs; ++i) {
264    registry->RegisterBooleanPref(
265        language_prefs::kMozcBooleanPrefs[i].pref_name,
266        language_prefs::kMozcBooleanPrefs[i].default_pref_value,
267        language_prefs::kMozcBooleanPrefs[i].sync_status);
268  }
269  for (size_t i = 0; i < language_prefs::kNumMozcMultipleChoicePrefs; ++i) {
270    registry->RegisterStringPref(
271        language_prefs::kMozcMultipleChoicePrefs[i].pref_name,
272        language_prefs::kMozcMultipleChoicePrefs[i].default_pref_value,
273        language_prefs::kMozcMultipleChoicePrefs[i].sync_status);
274  }
275  for (size_t i = 0; i < language_prefs::kNumMozcIntegerPrefs; ++i) {
276    registry->RegisterIntegerPref(
277        language_prefs::kMozcIntegerPrefs[i].pref_name,
278        language_prefs::kMozcIntegerPrefs[i].default_pref_value,
279        language_prefs::kMozcIntegerPrefs[i].sync_status);
280  }
281  registry->RegisterIntegerPref(
282      prefs::kLanguageRemapSearchKeyTo,
283      input_method::kSearchKey,
284      user_prefs::PrefRegistrySyncable::SYNCABLE_PRIORITY_PREF);
285  registry->RegisterIntegerPref(
286      prefs::kLanguageRemapControlKeyTo,
287      input_method::kControlKey,
288      user_prefs::PrefRegistrySyncable::SYNCABLE_PRIORITY_PREF);
289  registry->RegisterIntegerPref(
290      prefs::kLanguageRemapAltKeyTo,
291      input_method::kAltKey,
292      user_prefs::PrefRegistrySyncable::SYNCABLE_PRIORITY_PREF);
293  // We don't sync the CapsLock remapping pref, since the UI hides this pref
294  // on certain devices, so syncing a non-default value to a device that
295  // doesn't allow changing the pref would be odd. http://crbug.com/167237
296  registry->RegisterIntegerPref(
297      prefs::kLanguageRemapCapsLockKeyTo,
298      input_method::kCapsLockKey,
299      user_prefs::PrefRegistrySyncable::UNSYNCABLE_PREF);
300  registry->RegisterIntegerPref(
301      prefs::kLanguageRemapDiamondKeyTo,
302      input_method::kControlKey,
303      user_prefs::PrefRegistrySyncable::SYNCABLE_PRIORITY_PREF);
304  // We don't sync the following keyboard prefs since they are not user-
305  // configurable.
306  registry->RegisterBooleanPref(
307      prefs::kLanguageXkbAutoRepeatEnabled,
308      true,
309      user_prefs::PrefRegistrySyncable::UNSYNCABLE_PREF);
310  registry->RegisterIntegerPref(
311      prefs::kLanguageXkbAutoRepeatDelay,
312      language_prefs::kXkbAutoRepeatDelayInMs,
313      user_prefs::PrefRegistrySyncable::UNSYNCABLE_PREF);
314  registry->RegisterIntegerPref(
315      prefs::kLanguageXkbAutoRepeatInterval,
316      language_prefs::kXkbAutoRepeatIntervalInMs,
317      user_prefs::PrefRegistrySyncable::UNSYNCABLE_PREF);
318
319  // Mobile plan notifications default to on.
320  registry->RegisterBooleanPref(
321      prefs::kShowPlanNotifications,
322      true,
323      user_prefs::PrefRegistrySyncable::SYNCABLE_PREF);
324
325  // 3G first-time usage promo will be shown at least once.
326  registry->RegisterBooleanPref(
327      prefs::kShow3gPromoNotification,
328      true,
329      user_prefs::PrefRegistrySyncable::UNSYNCABLE_PREF);
330
331  // Initially all existing users would see "What's new" for current version
332  // after update.
333  registry->RegisterStringPref(prefs::kChromeOSReleaseNotesVersion,
334                               "0.0.0.0",
335                               user_prefs::PrefRegistrySyncable::SYNCABLE_PREF);
336
337  registry->RegisterBooleanPref(
338      prefs::kExternalStorageDisabled,
339      false,
340      user_prefs::PrefRegistrySyncable::UNSYNCABLE_PREF);
341
342  registry->RegisterStringPref(
343      prefs::kTermsOfServiceURL,
344      "",
345      user_prefs::PrefRegistrySyncable::UNSYNCABLE_PREF);
346
347  // TODO(achuith): Remove deprecated pref in M31. crbug.com/223480.
348  registry->RegisterBooleanPref(
349      kEnableTouchpadThreeFingerSwipe,
350      false,
351      user_prefs::PrefRegistrySyncable::UNSYNCABLE_PREF);
352
353  registry->RegisterBooleanPref(
354      prefs::kTouchHudProjectionEnabled,
355      false,
356      user_prefs::PrefRegistrySyncable::UNSYNCABLE_PREF);
357}
358
359void Preferences::InitUserPrefs(PrefServiceSyncable* prefs) {
360  prefs_ = prefs;
361
362  BooleanPrefMember::NamedChangeCallback callback =
363      base::Bind(&Preferences::OnPreferenceChanged, base::Unretained(this));
364
365  performance_tracing_enabled_.Init(prefs::kPerformanceTracingEnabled,
366                                    prefs, callback);
367  tap_to_click_enabled_.Init(prefs::kTapToClickEnabled, prefs, callback);
368  tap_dragging_enabled_.Init(prefs::kTapDraggingEnabled, prefs, callback);
369  three_finger_click_enabled_.Init(prefs::kEnableTouchpadThreeFingerClick,
370      prefs, callback);
371  natural_scroll_.Init(prefs::kNaturalScroll, prefs, callback);
372  a11y_spoken_feedback_enabled_.Init(prefs::kSpokenFeedbackEnabled,
373                                     prefs, callback);
374  a11y_high_contrast_enabled_.Init(prefs::kHighContrastEnabled,
375                                   prefs, callback);
376  a11y_screen_magnifier_enabled_.Init(prefs::kScreenMagnifierEnabled,
377                                      prefs, callback);
378  a11y_screen_magnifier_type_.Init(prefs::kScreenMagnifierType,
379                                   prefs, callback);
380  a11y_screen_magnifier_scale_.Init(prefs::kScreenMagnifierScale,
381                                    prefs, callback);
382  mouse_sensitivity_.Init(prefs::kMouseSensitivity, prefs, callback);
383  touchpad_sensitivity_.Init(prefs::kTouchpadSensitivity, prefs, callback);
384  use_24hour_clock_.Init(prefs::kUse24HourClock, prefs, callback);
385  disable_drive_.Init(prefs::kDisableDrive, prefs, callback);
386  disable_drive_over_cellular_.Init(prefs::kDisableDriveOverCellular,
387                                    prefs, callback);
388  disable_drive_hosted_files_.Init(prefs::kDisableDriveHostedFiles,
389                                   prefs, callback);
390  download_default_directory_.Init(prefs::kDownloadDefaultDirectory,
391                                   prefs, callback);
392  select_file_last_directory_.Init(prefs::kSelectFileLastDirectory,
393                                   prefs, callback);
394  save_file_default_directory_.Init(prefs::kSaveFileDefaultDirectory,
395                                    prefs, callback);
396  touch_hud_projection_enabled_.Init(prefs::kTouchHudProjectionEnabled,
397                                     prefs, callback);
398  primary_mouse_button_right_.Init(prefs::kPrimaryMouseButtonRight,
399                                   prefs, callback);
400  preferred_languages_.Init(prefs::kLanguagePreferredLanguages,
401                            prefs, callback);
402  preload_engines_.Init(prefs::kLanguagePreloadEngines, prefs, callback);
403  enabled_extension_imes_.Init(prefs::kLanguageEnabledExtensionImes,
404                               prefs, callback);
405  current_input_method_.Init(prefs::kLanguageCurrentInputMethod,
406                             prefs, callback);
407  previous_input_method_.Init(prefs::kLanguagePreviousInputMethod,
408                              prefs, callback);
409
410  for (size_t i = 0; i < language_prefs::kNumChewingBooleanPrefs; ++i) {
411    chewing_boolean_prefs_[i].Init(
412        language_prefs::kChewingBooleanPrefs[i].pref_name, prefs, callback);
413  }
414  for (size_t i = 0; i < language_prefs::kNumChewingMultipleChoicePrefs; ++i) {
415    chewing_multiple_choice_prefs_[i].Init(
416        language_prefs::kChewingMultipleChoicePrefs[i].pref_name,
417        prefs, callback);
418  }
419  chewing_hsu_sel_key_type_.Init(
420      language_prefs::kChewingHsuSelKeyType.pref_name, prefs, callback);
421  for (size_t i = 0; i < language_prefs::kNumChewingIntegerPrefs; ++i) {
422    chewing_integer_prefs_[i].Init(
423        language_prefs::kChewingIntegerPrefs[i].pref_name, prefs, callback);
424  }
425  hangul_keyboard_.Init(prefs::kLanguageHangulKeyboard, prefs, callback);
426  hangul_hanja_binding_keys_.Init(
427      prefs::kLanguageHangulHanjaBindingKeys, prefs, callback);
428  for (size_t i = 0; i < language_prefs::kNumPinyinBooleanPrefs; ++i) {
429    pinyin_boolean_prefs_[i].Init(
430        language_prefs::kPinyinBooleanPrefs[i].pref_name, prefs, callback);
431  }
432  for (size_t i = 0; i < language_prefs::kNumPinyinIntegerPrefs; ++i) {
433    pinyin_int_prefs_[i].Init(
434        language_prefs::kPinyinIntegerPrefs[i].pref_name, prefs, callback);
435  }
436  pinyin_double_pinyin_schema_.Init(
437      language_prefs::kPinyinDoublePinyinSchema.pref_name, prefs, callback);
438  for (size_t i = 0; i < language_prefs::kNumMozcBooleanPrefs; ++i) {
439    mozc_boolean_prefs_[i].Init(
440        language_prefs::kMozcBooleanPrefs[i].pref_name, prefs, callback);
441  }
442  for (size_t i = 0; i < language_prefs::kNumMozcMultipleChoicePrefs; ++i) {
443    mozc_multiple_choice_prefs_[i].Init(
444        language_prefs::kMozcMultipleChoicePrefs[i].pref_name, prefs, callback);
445  }
446  for (size_t i = 0; i < language_prefs::kNumMozcIntegerPrefs; ++i) {
447    mozc_integer_prefs_[i].Init(
448        language_prefs::kMozcIntegerPrefs[i].pref_name, prefs, callback);
449  }
450  xkb_auto_repeat_enabled_.Init(
451      prefs::kLanguageXkbAutoRepeatEnabled, prefs, callback);
452  xkb_auto_repeat_delay_pref_.Init(
453      prefs::kLanguageXkbAutoRepeatDelay, prefs, callback);
454  xkb_auto_repeat_interval_pref_.Init(
455      prefs::kLanguageXkbAutoRepeatInterval, prefs, callback);
456
457  // TODO(achuith): Remove deprecated pref in M31. crbug.com/223480.
458  prefs->ClearPref(kEnableTouchpadThreeFingerSwipe);
459}
460
461void Preferences::Init(PrefServiceSyncable* prefs) {
462  InitUserPrefs(prefs);
463
464  // This causes OnIsSyncingChanged to be called when the value of
465  // PrefService::IsSyncing() changes.
466  prefs->AddObserver(this);
467
468  // Initialize preferences to currently saved state.
469  NotifyPrefChanged(NULL);
470
471  // If a guest is logged in, initialize the prefs as if this is the first
472  // login.
473  if (CommandLine::ForCurrentProcess()->HasSwitch(switches::kGuestSession)) {
474    LoginUtils::Get()->SetFirstLoginPrefs(prefs);
475  }
476}
477
478void Preferences::InitUserPrefsForTesting(PrefServiceSyncable* prefs) {
479  InitUserPrefs(prefs);
480}
481
482void Preferences::SetInputMethodListForTesting() {
483  SetInputMethodList();
484}
485
486void Preferences::OnPreferenceChanged(const std::string& pref_name) {
487  NotifyPrefChanged(&pref_name);
488}
489
490void Preferences::NotifyPrefChanged(const std::string* pref_name) {
491  if (!pref_name || *pref_name == prefs::kPerformanceTracingEnabled) {
492    const bool enabled = performance_tracing_enabled_.GetValue();
493    if (enabled)
494      tracing_manager_ = TracingManager::Create();
495    else
496      tracing_manager_.reset();
497  }
498  if (!pref_name || *pref_name == prefs::kTapToClickEnabled) {
499    const bool enabled = tap_to_click_enabled_.GetValue();
500    system::touchpad_settings::SetTapToClick(enabled);
501    if (pref_name)
502      UMA_HISTOGRAM_BOOLEAN("Touchpad.TapToClick.Changed", enabled);
503    else
504      UMA_HISTOGRAM_BOOLEAN("Touchpad.TapToClick.Started", enabled);
505
506    // Save owner preference in local state to use on login screen.
507    if (chromeos::UserManager::Get()->IsCurrentUserOwner()) {
508      PrefService* prefs = g_browser_process->local_state();
509      if (prefs->GetBoolean(prefs::kOwnerTapToClickEnabled) != enabled)
510        prefs->SetBoolean(prefs::kOwnerTapToClickEnabled, enabled);
511    }
512  }
513  if (!pref_name || *pref_name == prefs::kTapDraggingEnabled) {
514    const bool enabled = tap_dragging_enabled_.GetValue();
515    system::touchpad_settings::SetTapDragging(enabled);
516    if (pref_name)
517      UMA_HISTOGRAM_BOOLEAN("Touchpad.TapDragging.Changed", enabled);
518    else
519      UMA_HISTOGRAM_BOOLEAN("Touchpad.TapDragging.Started", enabled);
520  }
521  if (!pref_name || *pref_name == prefs::kEnableTouchpadThreeFingerClick) {
522    const bool enabled = three_finger_click_enabled_.GetValue();
523    system::touchpad_settings::SetThreeFingerClick(enabled);
524    if (pref_name)
525      UMA_HISTOGRAM_BOOLEAN("Touchpad.ThreeFingerClick.Changed", enabled);
526    else
527      UMA_HISTOGRAM_BOOLEAN("Touchpad.ThreeFingerClick.Started", enabled);
528  }
529  if (!pref_name || *pref_name == prefs::kNaturalScroll) {
530    // Force natural scroll default if we've sync'd and if the cmd line arg is
531    // set.
532    ForceNaturalScrollDefault();
533
534    const bool enabled = natural_scroll_.GetValue();
535    DVLOG(1) << "Natural scroll set to " << enabled;
536    ui::SetNaturalScroll(enabled);
537    if (pref_name)
538      UMA_HISTOGRAM_BOOLEAN("Touchpad.NaturalScroll.Changed", enabled);
539    else
540      UMA_HISTOGRAM_BOOLEAN("Touchpad.NaturalScroll.Started", enabled);
541  }
542  if (!pref_name || *pref_name == prefs::kMouseSensitivity) {
543    const int sensitivity = mouse_sensitivity_.GetValue();
544    system::mouse_settings::SetSensitivity(sensitivity);
545    if (pref_name) {
546      UMA_HISTOGRAM_ENUMERATION("Mouse.PointerSensitivity.Changed",
547                                sensitivity,
548                                system::kMaxPointerSensitivity + 1);
549    } else {
550      UMA_HISTOGRAM_ENUMERATION("Mouse.PointerSensitivity.Started",
551                                sensitivity,
552                                system::kMaxPointerSensitivity + 1);
553    }
554  }
555  if (!pref_name || *pref_name == prefs::kTouchpadSensitivity) {
556    const int sensitivity = touchpad_sensitivity_.GetValue();
557    system::touchpad_settings::SetSensitivity(sensitivity);
558    if (pref_name) {
559      UMA_HISTOGRAM_ENUMERATION("Touchpad.PointerSensitivity.Changed",
560                                sensitivity,
561                                system::kMaxPointerSensitivity + 1);
562    } else {
563      UMA_HISTOGRAM_ENUMERATION("Touchpad.PointerSensitivity.Started",
564                                sensitivity,
565                                system::kMaxPointerSensitivity + 1);
566    }
567  }
568  if (!pref_name || *pref_name == prefs::kPrimaryMouseButtonRight) {
569    const bool right = primary_mouse_button_right_.GetValue();
570    system::mouse_settings::SetPrimaryButtonRight(right);
571    if (pref_name)
572      UMA_HISTOGRAM_BOOLEAN("Mouse.PrimaryButtonRight.Changed", right);
573    else
574      UMA_HISTOGRAM_BOOLEAN("Mouse.PrimaryButtonRight.Started", right);
575
576    // Save owner preference in local state to use on login screen.
577    if (chromeos::UserManager::Get()->IsCurrentUserOwner()) {
578      PrefService* prefs = g_browser_process->local_state();
579      if (prefs->GetBoolean(prefs::kOwnerPrimaryMouseButtonRight) != right)
580        prefs->SetBoolean(prefs::kOwnerPrimaryMouseButtonRight, right);
581    }
582  }
583  if (!pref_name || *pref_name == prefs::kDownloadDefaultDirectory) {
584    const base::FilePath pref_path = download_default_directory_.GetValue();
585    // TODO(haruki): Remove this when migration completes. crbug.com/229304.
586    if (drive::util::NeedsNamespaceMigration(pref_path)) {
587      prefs_->SetFilePath(prefs::kDownloadDefaultDirectory,
588                          drive::util::ConvertToMyDriveNamespace(pref_path));
589    }
590
591    const bool default_download_to_drive = drive::util::IsUnderDriveMountPoint(
592        download_default_directory_.GetValue());
593    if (pref_name)
594      UMA_HISTOGRAM_BOOLEAN(
595          "FileBrowser.DownloadDestination.IsGoogleDrive.Changed",
596          default_download_to_drive);
597    else
598      UMA_HISTOGRAM_BOOLEAN(
599          "FileBrowser.DownloadDestination.IsGoogleDrive.Started",
600          default_download_to_drive);
601  }
602  if (!pref_name || *pref_name == prefs::kSelectFileLastDirectory) {
603    const base::FilePath pref_path = select_file_last_directory_.GetValue();
604    // This pref can contain a Drive path, which needs to be updated due to
605    // namespaces introduced by crbug.com/174233.
606    // TODO(haruki): Remove this when migration completes. crbug.com/229304.
607    if (drive::util::NeedsNamespaceMigration(pref_path)) {
608      prefs_->SetFilePath(prefs::kSelectFileLastDirectory,
609                          drive::util::ConvertToMyDriveNamespace(pref_path));
610    }
611  }
612  if (!pref_name || *pref_name == prefs::kSaveFileDefaultDirectory) {
613    const base::FilePath pref_path = save_file_default_directory_.GetValue();
614    // This pref can contain a Drive path, which needs to be updated due to
615    // namespaces introduced by crbug.com/174233.
616    // TODO(haruki): Remove this when migration completes. crbug.com/229304.
617    if (drive::util::NeedsNamespaceMigration(pref_path)) {
618      prefs_->SetFilePath(prefs::kSaveFileDefaultDirectory,
619                          drive::util::ConvertToMyDriveNamespace(pref_path));
620    }
621  }
622  if (!pref_name || *pref_name == prefs::kTouchHudProjectionEnabled) {
623    const bool enabled = touch_hud_projection_enabled_.GetValue();
624    ash::Shell::GetInstance()->SetTouchHudProjectionEnabled(enabled);
625  }
626
627  if (!pref_name || *pref_name == prefs::kLanguagePreferredLanguages) {
628    // Unlike kLanguagePreloadEngines and some other input method
629    // preferencs, we don't need to send this to ibus-daemon.
630  }
631
632  if (!pref_name || *pref_name == prefs::kLanguageXkbAutoRepeatEnabled) {
633    const bool enabled = xkb_auto_repeat_enabled_.GetValue();
634    input_method::XKeyboard::SetAutoRepeatEnabled(enabled);
635  }
636  if (!pref_name || ((*pref_name == prefs::kLanguageXkbAutoRepeatDelay) ||
637                     (*pref_name == prefs::kLanguageXkbAutoRepeatInterval))) {
638    UpdateAutoRepeatRate();
639  }
640
641  if (!pref_name) {
642    SetInputMethodList();
643  } else if (*pref_name == prefs::kLanguagePreloadEngines) {
644    SetLanguageConfigStringListAsCSV(language_prefs::kGeneralSectionName,
645                                     language_prefs::kPreloadEnginesConfigName,
646                                     preload_engines_.GetValue());
647  }
648
649  if (!pref_name || *pref_name == prefs::kLanguageEnabledExtensionImes) {
650    std::string value(enabled_extension_imes_.GetValue());
651
652    std::vector<std::string> split_values;
653    if (!value.empty())
654      base::SplitString(value, ',', &split_values);
655
656    input_method_manager_->SetEnabledExtensionImes(&split_values);
657  }
658
659  // Change the download directory to the default value if a Drive directory is
660  // selected and Drive is disabled.
661  if (!pref_name || *pref_name == prefs::kDisableDrive) {
662    if (disable_drive_.GetValue()) {
663      if (drive::util::IsUnderDriveMountPoint(
664          download_default_directory_.GetValue())) {
665        prefs_->SetFilePath(prefs::kDownloadDefaultDirectory,
666                            DownloadPrefs::GetDefaultDownloadDirectory());
667      }
668    }
669  }
670}
671
672void Preferences::OnIsSyncingChanged() {
673  DVLOG(1) << "OnIsSyncingChanged";
674  ForceNaturalScrollDefault();
675}
676
677void Preferences::ForceNaturalScrollDefault() {
678  DVLOG(1) << "ForceNaturalScrollDefault";
679  if (CommandLine::ForCurrentProcess()->HasSwitch(
680          switches::kNaturalScrollDefault) &&
681      prefs_->IsSyncing() &&
682      !prefs_->GetUserPrefValue(prefs::kNaturalScroll)) {
683    DVLOG(1) << "Natural scroll forced to true";
684    natural_scroll_.SetValue(true);
685    UMA_HISTOGRAM_BOOLEAN("Touchpad.NaturalScroll.Forced", true);
686  }
687}
688
689void Preferences::SetLanguageConfigStringListAsCSV(const char* section,
690                                                   const char* name,
691                                                   const std::string& value) {
692  VLOG(1) << "Setting " << name << " to '" << value << "'";
693
694  std::vector<std::string> split_values;
695  if (!value.empty())
696    base::SplitString(value, ',', &split_values);
697
698  if (section == std::string(language_prefs::kGeneralSectionName) &&
699      name == std::string(language_prefs::kPreloadEnginesConfigName)) {
700    // TODO(nona): Remove this function after few milestones are passed.
701    //             (http://crbug.com/236747)
702    if (input_method_manager_->MigrateOldInputMethods(&split_values))
703      preload_engines_.SetValue(JoinString(split_values, ','));
704    input_method_manager_->EnableInputMethods(split_values);
705    return;
706  }
707}
708
709void Preferences::SetInputMethodList() {
710  // When |preload_engines_| are set, InputMethodManager::ChangeInputMethod()
711  // might be called to change the current input method to the first one in the
712  // |preload_engines_| list. This also updates previous/current input method
713  // prefs. That's why GetValue() calls are placed before the
714  // SetLanguageConfigStringListAsCSV() call below.
715  const std::string previous_input_method_id =
716      previous_input_method_.GetValue();
717  const std::string current_input_method_id = current_input_method_.GetValue();
718  SetLanguageConfigStringListAsCSV(language_prefs::kGeneralSectionName,
719                                   language_prefs::kPreloadEnginesConfigName,
720                                   preload_engines_.GetValue());
721
722  // ChangeInputMethod() has to be called AFTER the value of |preload_engines_|
723  // is sent to the InputMethodManager. Otherwise, the ChangeInputMethod request
724  // might be ignored as an invalid input method ID. The ChangeInputMethod()
725  // calls are also necessary to restore the previous/current input method prefs
726  // which could have been modified by the SetLanguageConfigStringListAsCSV call
727  // above to the original state.
728  if (!previous_input_method_id.empty())
729    input_method_manager_->ChangeInputMethod(previous_input_method_id);
730  if (!current_input_method_id.empty())
731    input_method_manager_->ChangeInputMethod(current_input_method_id);
732}
733
734void Preferences::UpdateAutoRepeatRate() {
735  // Avoid setting repeat rate on desktop dev environment.
736  if (!base::chromeos::IsRunningOnChromeOS())
737    return;
738
739  input_method::AutoRepeatRate rate;
740  rate.initial_delay_in_ms = xkb_auto_repeat_delay_pref_.GetValue();
741  rate.repeat_interval_in_ms = xkb_auto_repeat_interval_pref_.GetValue();
742  DCHECK(rate.initial_delay_in_ms > 0);
743  DCHECK(rate.repeat_interval_in_ms > 0);
744  input_method::XKeyboard::SetAutoRepeatRate(rate);
745}
746
747void Preferences::OnTouchHudProjectionToggled(bool enabled) {
748  if (touch_hud_projection_enabled_.GetValue() == enabled)
749    return;
750
751  touch_hud_projection_enabled_.SetValue(enabled);
752}
753
754}  // namespace chromeos
755