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_util.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::SYNCABLE_PRIORITY_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  // Do not check |*pref_name| of the prefs for remembering current/previous
660  // input methods here. We're only interested in initial values of the prefs.
661
662  // TODO(nona): remove all IME preference entries. crbug.com/256102
663  for (size_t i = 0; i < language_prefs::kNumChewingBooleanPrefs; ++i) {
664    if (!pref_name ||
665        *pref_name == language_prefs::kChewingBooleanPrefs[i].pref_name) {
666      SetLanguageConfigBoolean(
667          language_prefs::kChewingSectionName,
668          language_prefs::kChewingBooleanPrefs[i].ibus_config_name,
669          chewing_boolean_prefs_[i].GetValue());
670    }
671  }
672  for (size_t i = 0; i < language_prefs::kNumChewingMultipleChoicePrefs; ++i) {
673    if (!pref_name ||
674        *pref_name ==
675        language_prefs::kChewingMultipleChoicePrefs[i].pref_name) {
676      SetLanguageConfigString(
677          language_prefs::kChewingSectionName,
678          language_prefs::kChewingMultipleChoicePrefs[i].ibus_config_name,
679          chewing_multiple_choice_prefs_[i].GetValue());
680    }
681  }
682  if (!pref_name ||
683      *pref_name == language_prefs::kChewingHsuSelKeyType.pref_name) {
684    SetLanguageConfigInteger(
685        language_prefs::kChewingSectionName,
686        language_prefs::kChewingHsuSelKeyType.ibus_config_name,
687        chewing_hsu_sel_key_type_.GetValue());
688  }
689  for (size_t i = 0; i < language_prefs::kNumChewingIntegerPrefs; ++i) {
690    if (!pref_name ||
691        *pref_name == language_prefs::kChewingIntegerPrefs[i].pref_name) {
692      SetLanguageConfigInteger(
693          language_prefs::kChewingSectionName,
694          language_prefs::kChewingIntegerPrefs[i].ibus_config_name,
695          chewing_integer_prefs_[i].GetValue());
696    }
697  }
698  if (!pref_name ||
699      *pref_name == prefs::kLanguageHangulKeyboard) {
700    std::vector<std::string> new_input_method_ids;
701    if (input_method_manager_->MigrateKoreanKeyboard(
702            hangul_keyboard_.GetValue(),
703            &new_input_method_ids)) {
704      preload_engines_.SetValue(JoinString(new_input_method_ids, ','));
705      hangul_keyboard_.SetValue("dummy_value_already_migrated");
706    }
707  }
708  if (!pref_name || *pref_name == prefs::kLanguageHangulHanjaBindingKeys) {
709    SetLanguageConfigString(language_prefs::kHangulSectionName,
710                            language_prefs::kHangulHanjaBindingKeysConfigName,
711                            hangul_hanja_binding_keys_.GetValue());
712  }
713  for (size_t i = 0; i < language_prefs::kNumPinyinBooleanPrefs; ++i) {
714    if (!pref_name ||
715        *pref_name == language_prefs::kPinyinBooleanPrefs[i].pref_name) {
716      SetLanguageConfigBoolean(
717          language_prefs::kPinyinSectionName,
718          language_prefs::kPinyinBooleanPrefs[i].ibus_config_name,
719          pinyin_boolean_prefs_[i].GetValue());
720    }
721  }
722  for (size_t i = 0; i < language_prefs::kNumPinyinIntegerPrefs; ++i) {
723    if (!pref_name ||
724        *pref_name == language_prefs::kPinyinIntegerPrefs[i].pref_name) {
725      SetLanguageConfigInteger(
726          language_prefs::kPinyinSectionName,
727          language_prefs::kPinyinIntegerPrefs[i].ibus_config_name,
728          pinyin_int_prefs_[i].GetValue());
729    }
730  }
731  if (!pref_name ||
732      *pref_name == language_prefs::kPinyinDoublePinyinSchema.pref_name) {
733    SetLanguageConfigInteger(
734        language_prefs::kPinyinSectionName,
735        language_prefs::kPinyinDoublePinyinSchema.ibus_config_name,
736        pinyin_double_pinyin_schema_.GetValue());
737  }
738  for (size_t i = 0; i < language_prefs::kNumMozcBooleanPrefs; ++i) {
739    if (!pref_name ||
740        *pref_name == language_prefs::kMozcBooleanPrefs[i].pref_name) {
741      SetLanguageConfigBoolean(
742          language_prefs::kMozcSectionName,
743          language_prefs::kMozcBooleanPrefs[i].ibus_config_name,
744          mozc_boolean_prefs_[i].GetValue());
745    }
746  }
747  for (size_t i = 0; i < language_prefs::kNumMozcMultipleChoicePrefs; ++i) {
748    if (!pref_name ||
749        *pref_name == language_prefs::kMozcMultipleChoicePrefs[i].pref_name) {
750      SetLanguageConfigString(
751          language_prefs::kMozcSectionName,
752          language_prefs::kMozcMultipleChoicePrefs[i].ibus_config_name,
753          mozc_multiple_choice_prefs_[i].GetValue());
754    }
755  }
756  for (size_t i = 0; i < language_prefs::kNumMozcIntegerPrefs; ++i) {
757    if (!pref_name ||
758        *pref_name == language_prefs::kMozcIntegerPrefs[i].pref_name) {
759      SetLanguageConfigInteger(
760          language_prefs::kMozcSectionName,
761          language_prefs::kMozcIntegerPrefs[i].ibus_config_name,
762          mozc_integer_prefs_[i].GetValue());
763    }
764  }
765
766  // Change the download directory to the default value if a Drive directory is
767  // selected and Drive is disabled.
768  if (!pref_name || *pref_name == prefs::kDisableDrive) {
769    if (disable_drive_.GetValue()) {
770      if (drive::util::IsUnderDriveMountPoint(
771          download_default_directory_.GetValue())) {
772        prefs_->SetFilePath(prefs::kDownloadDefaultDirectory,
773                            download_util::GetDefaultDownloadDirectory());
774      }
775    }
776  }
777}
778
779void Preferences::OnIsSyncingChanged() {
780  DVLOG(1) << "OnIsSyncingChanged";
781  ForceNaturalScrollDefault();
782}
783
784void Preferences::ForceNaturalScrollDefault() {
785  DVLOG(1) << "ForceNaturalScrollDefault";
786  if (CommandLine::ForCurrentProcess()->HasSwitch(
787          switches::kNaturalScrollDefault) &&
788      prefs_->IsSyncing() &&
789      !prefs_->GetUserPrefValue(prefs::kNaturalScroll)) {
790    DVLOG(1) << "Natural scroll forced to true";
791    natural_scroll_.SetValue(true);
792    UMA_HISTOGRAM_BOOLEAN("Touchpad.NaturalScroll.Forced", true);
793  }
794}
795
796void Preferences::SetLanguageConfigBoolean(const char* section,
797                                           const char* name,
798                                           bool value) {
799  input_method::InputMethodConfigValue config;
800  config.type = input_method::InputMethodConfigValue::kValueTypeBool;
801  config.bool_value = value;
802  input_method_manager_->SetInputMethodConfig(section, name, config);
803}
804
805void Preferences::SetLanguageConfigInteger(const char* section,
806                                           const char* name,
807                                           int value) {
808  input_method::InputMethodConfigValue config;
809  config.type = input_method::InputMethodConfigValue::kValueTypeInt;
810  config.int_value = value;
811  input_method_manager_->SetInputMethodConfig(section, name, config);
812}
813
814void Preferences::SetLanguageConfigString(const char* section,
815                                          const char* name,
816                                          const std::string& value) {
817  input_method::InputMethodConfigValue config;
818  config.type = input_method::InputMethodConfigValue::kValueTypeString;
819  config.string_value = value;
820  input_method_manager_->SetInputMethodConfig(section, name, config);
821}
822
823void Preferences::SetLanguageConfigStringList(
824    const char* section,
825    const char* name,
826    const std::vector<std::string>& values) {
827  input_method::InputMethodConfigValue config;
828  config.type = input_method::InputMethodConfigValue::kValueTypeStringList;
829  for (size_t i = 0; i < values.size(); ++i)
830    config.string_list_value.push_back(values[i]);
831
832  input_method_manager_->SetInputMethodConfig(section, name, config);
833}
834
835void Preferences::SetLanguageConfigStringListAsCSV(const char* section,
836                                                   const char* name,
837                                                   const std::string& value) {
838  VLOG(1) << "Setting " << name << " to '" << value << "'";
839
840  std::vector<std::string> split_values;
841  if (!value.empty())
842    base::SplitString(value, ',', &split_values);
843
844  if (section == std::string(language_prefs::kGeneralSectionName) &&
845      name == std::string(language_prefs::kPreloadEnginesConfigName)) {
846    // TODO(nona): Remove this function after few milestones are passed.
847    //             (http://crbug.com/236747)
848    if (input_method_manager_->MigrateOldInputMethods(&split_values))
849      preload_engines_.SetValue(JoinString(split_values, ','));
850    input_method_manager_->EnableInputMethods(split_values);
851    return;
852  }
853
854  // We should call the cros API even when |value| is empty, to disable default
855  // config.
856  SetLanguageConfigStringList(section, name, split_values);
857}
858
859void Preferences::SetInputMethodList() {
860  // When |preload_engines_| are set, InputMethodManager::ChangeInputMethod()
861  // might be called to change the current input method to the first one in the
862  // |preload_engines_| list. This also updates previous/current input method
863  // prefs. That's why GetValue() calls are placed before the
864  // SetLanguageConfigStringListAsCSV() call below.
865  const std::string previous_input_method_id =
866      previous_input_method_.GetValue();
867  const std::string current_input_method_id = current_input_method_.GetValue();
868  SetLanguageConfigStringListAsCSV(language_prefs::kGeneralSectionName,
869                                   language_prefs::kPreloadEnginesConfigName,
870                                   preload_engines_.GetValue());
871
872  // ChangeInputMethod() has to be called AFTER the value of |preload_engines_|
873  // is sent to the InputMethodManager. Otherwise, the ChangeInputMethod request
874  // might be ignored as an invalid input method ID. The ChangeInputMethod()
875  // calls are also necessary to restore the previous/current input method prefs
876  // which could have been modified by the SetLanguageConfigStringListAsCSV call
877  // above to the original state.
878  if (!previous_input_method_id.empty())
879    input_method_manager_->ChangeInputMethod(previous_input_method_id);
880  if (!current_input_method_id.empty())
881    input_method_manager_->ChangeInputMethod(current_input_method_id);
882}
883
884void Preferences::UpdateAutoRepeatRate() {
885  // Avoid setting repeat rate on desktop dev environment.
886  if (!base::chromeos::IsRunningOnChromeOS())
887    return;
888
889  input_method::AutoRepeatRate rate;
890  rate.initial_delay_in_ms = xkb_auto_repeat_delay_pref_.GetValue();
891  rate.repeat_interval_in_ms = xkb_auto_repeat_interval_pref_.GetValue();
892  DCHECK(rate.initial_delay_in_ms > 0);
893  DCHECK(rate.repeat_interval_in_ms > 0);
894  input_method::XKeyboard::SetAutoRepeatRate(rate);
895}
896
897void Preferences::OnTouchHudProjectionToggled(bool enabled) {
898  if (touch_hud_projection_enabled_.GetValue() == enabled)
899    return;
900
901  touch_hud_projection_enabled_.SetValue(enabled);
902}
903
904}  // namespace chromeos
905