| // Copyright (c) 2012 The Chromium Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #include "chrome/browser/chromeos/preferences.h" |
| |
| #include <vector> |
| |
| #include "ash/ash_constants.h" |
| #include "ash/autoclick/autoclick_controller.h" |
| #include "ash/public/cpp/ash_pref_names.h" |
| #include "ash/shell.h" |
| #include "base/command_line.h" |
| #include "base/i18n/time_formatting.h" |
| #include "base/metrics/histogram_macros.h" |
| #include "base/strings/string_split.h" |
| #include "base/strings/string_util.h" |
| #include "base/strings/utf_string_conversions.h" |
| #include "chrome/browser/browser_process.h" |
| #include "chrome/browser/chrome_notification_types.h" |
| #include "chrome/browser/chromeos/accessibility/magnification_manager.h" |
| #include "chrome/browser/chromeos/ash_config.h" |
| #include "chrome/browser/chromeos/drive/file_system_util.h" |
| #include "chrome/browser/chromeos/input_method/input_method_syncer.h" |
| #include "chrome/browser/chromeos/login/session/user_session_manager.h" |
| #include "chrome/browser/chromeos/net/wake_on_wifi_manager.h" |
| #include "chrome/browser/chromeos/profiles/profile_helper.h" |
| #include "chrome/browser/chromeos/settings/cros_settings.h" |
| #include "chrome/browser/chromeos/system/input_device_settings.h" |
| #include "chrome/browser/chromeos/system/timezone_resolver_manager.h" |
| #include "chrome/browser/chromeos/system/timezone_util.h" |
| #include "chrome/browser/download/download_prefs.h" |
| #include "chrome/browser/prefs/pref_service_syncable_util.h" |
| #include "chrome/browser/ui/ash/ash_util.h" |
| #include "chrome/browser/ui/ash/system_tray_client.h" |
| #include "chrome/common/chrome_features.h" |
| #include "chrome/common/pref_names.h" |
| #include "chromeos/chromeos_switches.h" |
| #include "chromeos/settings/cros_settings_names.h" |
| #include "chromeos/system/devicemode.h" |
| #include "chromeos/system/statistics_provider.h" |
| #include "chromeos/timezone/timezone_resolver.h" |
| #include "components/drive/drive_pref_names.h" |
| #include "components/feedback/tracing_manager.h" |
| #include "components/policy/proto/chrome_device_policy.pb.h" |
| #include "components/pref_registry/pref_registry_syncable.h" |
| #include "components/prefs/pref_member.h" |
| #include "components/prefs/pref_registry_simple.h" |
| #include "components/prefs/scoped_user_pref_update.h" |
| #include "components/sync_preferences/pref_service_syncable.h" |
| #include "components/user_manager/known_user.h" |
| #include "components/user_manager/user.h" |
| #include "components/user_manager/user_manager.h" |
| #include "content/public/browser/browser_thread.h" |
| #include "third_party/cros_system_api/dbus/update_engine/dbus-constants.h" |
| #include "third_party/icu/source/i18n/unicode/timezone.h" |
| #include "ui/base/ime/chromeos/extension_ime_util.h" |
| #include "ui/base/ime/chromeos/ime_keyboard.h" |
| #include "ui/base/ime/chromeos/input_method_manager.h" |
| #include "ui/chromeos/events/modifier_key.h" |
| #include "ui/chromeos/events/pref_names.h" |
| #include "ui/display/manager/display_manager.h" |
| #include "ui/events/event_constants.h" |
| #include "ui/events/event_utils.h" |
| #include "url/gurl.h" |
| |
| namespace chromeos { |
| |
| namespace { |
| |
| static const char kFallbackInputMethodLocale[] = "en-US"; |
| |
| // The keyboard preferences that determine how we remap modifier keys. These |
| // preferences will be saved in global user preferences dictionary so that they |
| // can be used on signin screen. |
| const char* const kLanguageRemapPrefs[] = { |
| prefs::kLanguageRemapSearchKeyTo, prefs::kLanguageRemapControlKeyTo, |
| prefs::kLanguageRemapAltKeyTo, prefs::kLanguageRemapCapsLockKeyTo, |
| prefs::kLanguageRemapEscapeKeyTo, prefs::kLanguageRemapBackspaceKeyTo, |
| prefs::kLanguageRemapDiamondKeyTo}; |
| |
| // Migrates kResolveTimezoneByGeolocation value to |
| // kResolveTimezoneByGeolocationMethod. |
| // Default preference value will become another default value. |
| // TODO(alemate): https://crbug.com/783367 Remove outdated prefs. |
| void TryMigrateToResolveTimezoneByGeolocationMethod(PrefService* prefs) { |
| if (prefs->GetBoolean(prefs::kResolveTimezoneByGeolocationMigratedToMethod)) |
| return; |
| |
| prefs->SetBoolean(prefs::kResolveTimezoneByGeolocationMigratedToMethod, true); |
| const PrefService::Preference* old_preference = |
| prefs->FindPreference(prefs::kResolveTimezoneByGeolocation); |
| if (old_preference->IsDefaultValue()) |
| return; |
| |
| const PrefService::Preference* new_preference = |
| prefs->FindPreference(prefs::kResolveTimezoneByGeolocationMethod); |
| if (!new_preference->IsDefaultValue()) |
| return; |
| |
| const system::TimeZoneResolverManager::TimeZoneResolveMethod method( |
| old_preference->GetValue()->GetBool() |
| ? system::TimeZoneResolverManager::TimeZoneResolveMethod::IP_ONLY |
| : system::TimeZoneResolverManager::TimeZoneResolveMethod::DISABLED); |
| prefs->SetInteger(prefs::kResolveTimezoneByGeolocationMethod, |
| static_cast<int>(method)); |
| } |
| |
| } // namespace |
| |
| Preferences::Preferences() |
| : Preferences(input_method::InputMethodManager::Get()) {} |
| |
| Preferences::Preferences(input_method::InputMethodManager* input_method_manager) |
| : prefs_(NULL), |
| input_method_manager_(input_method_manager), |
| user_(NULL), |
| user_is_primary_(false) {} |
| |
| Preferences::~Preferences() { |
| prefs_->RemoveObserver(this); |
| user_manager::UserManager::Get()->RemoveSessionStateObserver(this); |
| } |
| |
| // static |
| void Preferences::RegisterPrefs(PrefRegistrySimple* registry) { |
| registry->RegisterBooleanPref(prefs::kOwnerPrimaryMouseButtonRight, false); |
| registry->RegisterBooleanPref(prefs::kOwnerTapToClickEnabled, true); |
| // TODO(jamescook): Move ownership and registration into ash. |
| registry->RegisterBooleanPref( |
| ash::prefs::kAccessibilityVirtualKeyboardEnabled, false); |
| registry->RegisterStringPref(prefs::kLogoutStartedLast, std::string()); |
| registry->RegisterStringPref(prefs::kSigninScreenTimezone, std::string()); |
| registry->RegisterBooleanPref(prefs::kResolveDeviceTimezoneByGeolocation, |
| true); |
| registry->RegisterIntegerPref( |
| prefs::kResolveDeviceTimezoneByGeolocationMethod, |
| static_cast<int>( |
| system::TimeZoneResolverManager::TimeZoneResolveMethod::IP_ONLY)); |
| registry->RegisterIntegerPref( |
| prefs::kSystemTimezoneAutomaticDetectionPolicy, |
| enterprise_management::SystemTimezoneProto::USERS_DECIDE); |
| |
| registry->RegisterDictionaryPref(ash::prefs::kWallpaperColors, |
| PrefRegistry::PUBLIC); |
| registry->RegisterStringPref(prefs::kMinimumAllowedChromeVersion, ""); |
| } |
| |
| // static |
| void Preferences::RegisterProfilePrefs( |
| user_prefs::PrefRegistrySyncable* registry) { |
| std::string hardware_keyboard_id; |
| // TODO(yusukes): Remove the runtime hack. |
| if (IsRunningAsSystemCompositor()) { |
| DCHECK(g_browser_process); |
| PrefService* local_state = g_browser_process->local_state(); |
| DCHECK(local_state); |
| hardware_keyboard_id = |
| local_state->GetString(prefs::kHardwareKeyboardLayout); |
| } else { |
| hardware_keyboard_id = "xkb:us::eng"; // only for testing. |
| } |
| |
| registry->RegisterBooleanPref(prefs::kPerformanceTracingEnabled, false); |
| |
| registry->RegisterBooleanPref( |
| prefs::kTapToClickEnabled, |
| true, |
| user_prefs::PrefRegistrySyncable::SYNCABLE_PRIORITY_PREF); |
| registry->RegisterBooleanPref( |
| prefs::kTapDraggingEnabled, |
| false, |
| user_prefs::PrefRegistrySyncable::SYNCABLE_PRIORITY_PREF); |
| registry->RegisterBooleanPref(prefs::kEnableTouchpadThreeFingerClick, false); |
| // This preference can only be set to true by policy or command_line flag |
| // and it should not carry over to sessions were neither of these is set. |
| registry->RegisterBooleanPref(prefs::kUnifiedDesktopEnabledByDefault, false, |
| PrefRegistry::NO_REGISTRATION_FLAGS); |
| registry->RegisterBooleanPref( |
| prefs::kNaturalScroll, base::CommandLine::ForCurrentProcess()->HasSwitch( |
| switches::kNaturalScrollDefault), |
| user_prefs::PrefRegistrySyncable::SYNCABLE_PRIORITY_PREF); |
| registry->RegisterBooleanPref( |
| prefs::kPrimaryMouseButtonRight, |
| false, |
| user_prefs::PrefRegistrySyncable::SYNCABLE_PRIORITY_PREF); |
| registry->RegisterBooleanPref( |
| prefs::kMouseReverseScroll, false, |
| user_prefs::PrefRegistrySyncable::SYNCABLE_PRIORITY_PREF); |
| registry->RegisterBooleanPref(prefs::kLabsMediaplayerEnabled, false); |
| registry->RegisterBooleanPref(prefs::kLabsAdvancedFilesystemEnabled, false); |
| |
| // TODO(jamescook): Move ownership and registration into ash. This will need |
| // changes to policy::RecommendationRestorer which requires that prefs are |
| // available immediately during startup. |
| registry->RegisterBooleanPref( |
| ash::prefs::kAccessibilityStickyKeysEnabled, false, |
| user_prefs::PrefRegistrySyncable::SYNCABLE_PREF); |
| registry->RegisterBooleanPref( |
| ash::prefs::kAccessibilityLargeCursorEnabled, false, |
| user_prefs::PrefRegistrySyncable::SYNCABLE_PREF | PrefRegistry::PUBLIC); |
| registry->RegisterIntegerPref(ash::prefs::kAccessibilityLargeCursorDipSize, |
| ash::kDefaultLargeCursorSize, |
| PrefRegistry::PUBLIC); |
| registry->RegisterBooleanPref(ash::prefs::kAccessibilitySpokenFeedbackEnabled, |
| false); |
| registry->RegisterBooleanPref( |
| ash::prefs::kAccessibilityHighContrastEnabled, false, |
| user_prefs::PrefRegistrySyncable::SYNCABLE_PREF | PrefRegistry::PUBLIC); |
| registry->RegisterBooleanPref( |
| ash::prefs::kAccessibilityScreenMagnifierCenterFocus, true, |
| user_prefs::PrefRegistrySyncable::SYNCABLE_PREF); |
| registry->RegisterBooleanPref( |
| ash::prefs::kAccessibilityScreenMagnifierEnabled, false, |
| user_prefs::PrefRegistrySyncable::SYNCABLE_PREF | PrefRegistry::PUBLIC); |
| registry->RegisterDoublePref(ash::prefs::kAccessibilityScreenMagnifierScale, |
| std::numeric_limits<double>::min()); |
| registry->RegisterBooleanPref( |
| ash::prefs::kAccessibilityAutoclickEnabled, false, |
| user_prefs::PrefRegistrySyncable::SYNCABLE_PREF); |
| registry->RegisterIntegerPref( |
| ash::prefs::kAccessibilityAutoclickDelayMs, |
| static_cast<int>(ash::AutoclickController::GetDefaultAutoclickDelay() |
| .InMilliseconds()), |
| user_prefs::PrefRegistrySyncable::SYNCABLE_PREF); |
| registry->RegisterBooleanPref( |
| ash::prefs::kAccessibilityVirtualKeyboardEnabled, false, |
| user_prefs::PrefRegistrySyncable::SYNCABLE_PREF); |
| registry->RegisterBooleanPref( |
| ash::prefs::kAccessibilityMonoAudioEnabled, false, |
| user_prefs::PrefRegistrySyncable::SYNCABLE_PREF | PrefRegistry::PUBLIC); |
| registry->RegisterBooleanPref( |
| ash::prefs::kAccessibilityCaretHighlightEnabled, false, |
| user_prefs::PrefRegistrySyncable::SYNCABLE_PREF); |
| registry->RegisterBooleanPref( |
| ash::prefs::kAccessibilityCursorHighlightEnabled, false, |
| user_prefs::PrefRegistrySyncable::SYNCABLE_PREF); |
| registry->RegisterBooleanPref( |
| ash::prefs::kAccessibilityFocusHighlightEnabled, false, |
| user_prefs::PrefRegistrySyncable::SYNCABLE_PREF); |
| registry->RegisterBooleanPref( |
| ash::prefs::kAccessibilitySelectToSpeakEnabled, false, |
| user_prefs::PrefRegistrySyncable::SYNCABLE_PREF); |
| registry->RegisterBooleanPref( |
| ash::prefs::kAccessibilitySwitchAccessEnabled, false, |
| user_prefs::PrefRegistrySyncable::SYNCABLE_PREF); |
| registry->RegisterBooleanPref( |
| ash::prefs::kShouldAlwaysShowAccessibilityMenu, false, |
| user_prefs::PrefRegistrySyncable::SYNCABLE_PREF); |
| |
| registry->RegisterIntegerPref( |
| prefs::kMouseSensitivity, |
| 3, |
| user_prefs::PrefRegistrySyncable::SYNCABLE_PRIORITY_PREF); |
| registry->RegisterIntegerPref( |
| prefs::kTouchpadSensitivity, |
| 3, |
| user_prefs::PrefRegistrySyncable::SYNCABLE_PRIORITY_PREF); |
| registry->RegisterBooleanPref( |
| prefs::kUse24HourClock, |
| base::GetHourClockType() == base::k24HourClock, |
| user_prefs::PrefRegistrySyncable::SYNCABLE_PREF); |
| registry->RegisterBooleanPref( |
| drive::prefs::kDisableDrive, false, |
| user_prefs::PrefRegistrySyncable::SYNCABLE_PREF); |
| registry->RegisterBooleanPref( |
| drive::prefs::kDisableDriveOverCellular, true, |
| user_prefs::PrefRegistrySyncable::SYNCABLE_PREF); |
| registry->RegisterBooleanPref( |
| drive::prefs::kDisableDriveHostedFiles, false, |
| user_prefs::PrefRegistrySyncable::SYNCABLE_PREF); |
| // We don't sync prefs::kLanguageCurrentInputMethod and PreviousInputMethod |
| // because they're just used to track the logout state of the device. |
| registry->RegisterStringPref(prefs::kLanguageCurrentInputMethod, ""); |
| registry->RegisterStringPref(prefs::kLanguagePreviousInputMethod, ""); |
| registry->RegisterStringPref(prefs::kLanguagePreferredLanguages, |
| kFallbackInputMethodLocale); |
| registry->RegisterStringPref(prefs::kLanguagePreloadEngines, |
| hardware_keyboard_id); |
| registry->RegisterStringPref(prefs::kLanguageEnabledExtensionImes, ""); |
| |
| registry->RegisterIntegerPref( |
| prefs::kLanguageRemapSearchKeyTo, |
| static_cast<int>(ui::chromeos::ModifierKey::kSearchKey), |
| user_prefs::PrefRegistrySyncable::SYNCABLE_PRIORITY_PREF | |
| PrefRegistry::PUBLIC); // Used in ash. |
| registry->RegisterIntegerPref( |
| prefs::kLanguageRemapControlKeyTo, |
| static_cast<int>(ui::chromeos::ModifierKey::kControlKey), |
| user_prefs::PrefRegistrySyncable::SYNCABLE_PRIORITY_PREF); |
| registry->RegisterIntegerPref( |
| prefs::kLanguageRemapAltKeyTo, |
| static_cast<int>(ui::chromeos::ModifierKey::kAltKey), |
| user_prefs::PrefRegistrySyncable::SYNCABLE_PRIORITY_PREF); |
| // We don't sync the CapsLock remapping pref, since the UI hides this pref |
| // on certain devices, so syncing a non-default value to a device that |
| // doesn't allow changing the pref would be odd. http://crbug.com/167237 |
| registry->RegisterIntegerPref( |
| prefs::kLanguageRemapCapsLockKeyTo, |
| static_cast<int>(ui::chromeos::ModifierKey::kCapsLockKey)); |
| registry->RegisterIntegerPref( |
| prefs::kLanguageRemapEscapeKeyTo, |
| static_cast<int>(ui::chromeos::ModifierKey::kEscapeKey), |
| user_prefs::PrefRegistrySyncable::SYNCABLE_PRIORITY_PREF); |
| registry->RegisterIntegerPref( |
| prefs::kLanguageRemapBackspaceKeyTo, |
| static_cast<int>(ui::chromeos::ModifierKey::kBackspaceKey), |
| user_prefs::PrefRegistrySyncable::SYNCABLE_PRIORITY_PREF); |
| registry->RegisterIntegerPref( |
| prefs::kLanguageRemapDiamondKeyTo, |
| static_cast<int>(ui::chromeos::ModifierKey::kControlKey), |
| user_prefs::PrefRegistrySyncable::SYNCABLE_PRIORITY_PREF); |
| // The following pref isn't synced since the user may desire a different value |
| // depending on whether an external keyboard is attached to a particular |
| // device. |
| registry->RegisterBooleanPref(prefs::kLanguageSendFunctionKeys, false); |
| registry->RegisterBooleanPref( |
| prefs::kLanguageXkbAutoRepeatEnabled, |
| language_prefs::kXkbAutoRepeatEnabled, |
| user_prefs::PrefRegistrySyncable::SYNCABLE_PREF); |
| registry->RegisterIntegerPref( |
| prefs::kLanguageXkbAutoRepeatDelay, |
| language_prefs::kXkbAutoRepeatDelayInMs, |
| user_prefs::PrefRegistrySyncable::SYNCABLE_PREF); |
| registry->RegisterIntegerPref( |
| prefs::kLanguageXkbAutoRepeatInterval, |
| language_prefs::kXkbAutoRepeatIntervalInMs, |
| user_prefs::PrefRegistrySyncable::SYNCABLE_PREF); |
| |
| // Don't sync the note-taking app; it may not be installed on other devices. |
| registry->RegisterStringPref(prefs::kNoteTakingAppId, std::string()); |
| registry->RegisterBooleanPref(prefs::kNoteTakingAppEnabledOnLockScreen, true); |
| registry->RegisterListPref(prefs::kNoteTakingAppsLockScreenWhitelist); |
| registry->RegisterBooleanPref(prefs::kRestoreLastLockScreenNote, true); |
| registry->RegisterDictionaryPref(prefs::kNoteTakingAppsLockScreenToastShown); |
| |
| // We don't sync wake-on-wifi related prefs because they are device specific. |
| registry->RegisterBooleanPref(prefs::kWakeOnWifiDarkConnect, true); |
| |
| // 3G first-time usage promo will be shown at least once. |
| registry->RegisterBooleanPref(prefs::kShow3gPromoNotification, true); |
| |
| // Number of times Data Saver prompt has been shown on 3G data network. |
| registry->RegisterIntegerPref( |
| prefs::kDataSaverPromptsShown, |
| 0, |
| user_prefs::PrefRegistrySyncable::SYNCABLE_PREF); |
| |
| // Initially all existing users would see "What's new" for current version |
| // after update. |
| registry->RegisterStringPref(prefs::kChromeOSReleaseNotesVersion, |
| "0.0.0.0", |
| user_prefs::PrefRegistrySyncable::SYNCABLE_PREF); |
| |
| registry->RegisterBooleanPref(prefs::kExternalStorageDisabled, false); |
| |
| registry->RegisterBooleanPref(prefs::kExternalStorageReadOnly, false); |
| |
| registry->RegisterStringPref(prefs::kTermsOfServiceURL, ""); |
| |
| registry->RegisterBooleanPref(prefs::kTouchVirtualKeyboardEnabled, false); |
| |
| input_method::InputMethodSyncer::RegisterProfilePrefs(registry); |
| |
| std::string current_timezone_id; |
| if (chromeos::CrosSettings::IsInitialized()) { |
| // In unit tests CrosSettings is not always initialized. |
| chromeos::CrosSettings::Get()->GetString(kSystemTimezone, |
| ¤t_timezone_id); |
| } |
| // |current_timezone_id| will be empty if CrosSettings doesn't know the |
| // timezone yet. |
| registry->RegisterStringPref(prefs::kUserTimezone, current_timezone_id); |
| |
| registry->RegisterBooleanPref( |
| prefs::kResolveTimezoneByGeolocation, true, |
| user_prefs::PrefRegistrySyncable::SYNCABLE_PREF); |
| |
| registry->RegisterBooleanPref( |
| prefs::kResolveTimezoneByGeolocationMigratedToMethod, false, |
| user_prefs::PrefRegistrySyncable::SYNCABLE_PREF); |
| |
| registry->RegisterIntegerPref( |
| prefs::kResolveTimezoneByGeolocationMethod, |
| static_cast<int>( |
| system::TimeZoneResolverManager::TimeZoneResolveMethod::IP_ONLY), |
| user_prefs::PrefRegistrySyncable::SYNCABLE_PREF); |
| |
| registry->RegisterBooleanPref(prefs::kCaptivePortalAuthenticationIgnoresProxy, |
| true); |
| |
| registry->RegisterBooleanPref(prefs::kForceMaximizeOnFirstRun, false); |
| |
| registry->RegisterBooleanPref(prefs::kLanguageImeMenuActivated, false); |
| |
| registry->RegisterInt64Pref(prefs::kHatsLastInteractionTimestamp, |
| base::Time().ToInternalValue()); |
| |
| registry->RegisterInt64Pref(prefs::kHatsSurveyCycleEndTimestamp, |
| base::Time().ToInternalValue()); |
| |
| registry->RegisterBooleanPref(prefs::kHatsDeviceIsSelected, false); |
| |
| registry->RegisterBooleanPref(prefs::kPinUnlockFeatureNotificationShown, |
| false); |
| registry->RegisterBooleanPref( |
| prefs::kFingerprintUnlockFeatureNotificationShown, false); |
| |
| // We don't sync EOL related prefs because they are device specific. |
| registry->RegisterBooleanPref(prefs::kEolNotificationDismissed, false); |
| registry->RegisterIntegerPref(prefs::kEolStatus, |
| update_engine::EndOfLifeStatus::kSupported); |
| |
| registry->RegisterBooleanPref(prefs::kCastReceiverEnabled, false); |
| } |
| |
| void Preferences::InitUserPrefs(sync_preferences::PrefServiceSyncable* prefs) { |
| prefs_ = prefs; |
| |
| BooleanPrefMember::NamedChangeCallback callback = |
| base::Bind(&Preferences::OnPreferenceChanged, base::Unretained(this)); |
| |
| performance_tracing_enabled_.Init(prefs::kPerformanceTracingEnabled, |
| prefs, callback); |
| tap_to_click_enabled_.Init(prefs::kTapToClickEnabled, prefs, callback); |
| tap_dragging_enabled_.Init(prefs::kTapDraggingEnabled, prefs, callback); |
| three_finger_click_enabled_.Init(prefs::kEnableTouchpadThreeFingerClick, |
| prefs, callback); |
| unified_desktop_enabled_by_default_.Init( |
| prefs::kUnifiedDesktopEnabledByDefault, prefs, callback); |
| natural_scroll_.Init(prefs::kNaturalScroll, prefs, callback); |
| mouse_sensitivity_.Init(prefs::kMouseSensitivity, prefs, callback); |
| touchpad_sensitivity_.Init(prefs::kTouchpadSensitivity, prefs, callback); |
| primary_mouse_button_right_.Init(prefs::kPrimaryMouseButtonRight, |
| prefs, callback); |
| mouse_reverse_scroll_.Init(prefs::kMouseReverseScroll, prefs, callback); |
| download_default_directory_.Init(prefs::kDownloadDefaultDirectory, |
| prefs, callback); |
| preload_engines_.Init(prefs::kLanguagePreloadEngines, prefs, callback); |
| enabled_extension_imes_.Init(prefs::kLanguageEnabledExtensionImes, |
| prefs, callback); |
| current_input_method_.Init(prefs::kLanguageCurrentInputMethod, |
| prefs, callback); |
| previous_input_method_.Init(prefs::kLanguagePreviousInputMethod, |
| prefs, callback); |
| ime_menu_activated_.Init(prefs::kLanguageImeMenuActivated, prefs, callback); |
| // Notifies the system tray to remove the IME items. |
| if (base::FeatureList::IsEnabled(features::kOptInImeMenu) && |
| ime_menu_activated_.GetValue()) |
| input_method::InputMethodManager::Get()->ImeMenuActivationChanged(true); |
| |
| xkb_auto_repeat_enabled_.Init( |
| prefs::kLanguageXkbAutoRepeatEnabled, prefs, callback); |
| xkb_auto_repeat_delay_pref_.Init( |
| prefs::kLanguageXkbAutoRepeatDelay, prefs, callback); |
| xkb_auto_repeat_interval_pref_.Init( |
| prefs::kLanguageXkbAutoRepeatInterval, prefs, callback); |
| |
| wake_on_wifi_darkconnect_.Init(prefs::kWakeOnWifiDarkConnect, prefs, |
| callback); |
| |
| pref_change_registrar_.Init(prefs); |
| pref_change_registrar_.Add(prefs::kUserTimezone, callback); |
| pref_change_registrar_.Add(prefs::kResolveTimezoneByGeolocation, callback); |
| pref_change_registrar_.Add(prefs::kResolveTimezoneByGeolocationMethod, |
| callback); |
| pref_change_registrar_.Add(prefs::kUse24HourClock, callback); |
| for (auto* remap_pref : kLanguageRemapPrefs) |
| pref_change_registrar_.Add(remap_pref, callback); |
| } |
| |
| void Preferences::Init(Profile* profile, const user_manager::User* user) { |
| DCHECK(profile); |
| DCHECK(user); |
| sync_preferences::PrefServiceSyncable* prefs = |
| PrefServiceSyncableFromProfile(profile); |
| // This causes OnIsSyncingChanged to be called when the value of |
| // PrefService::IsSyncing() changes. |
| prefs->AddObserver(this); |
| user_ = user; |
| user_is_primary_ = |
| user_manager::UserManager::Get()->GetPrimaryUser() == user_; |
| InitUserPrefs(prefs); |
| |
| user_manager::UserManager::Get()->AddSessionStateObserver(this); |
| |
| UserSessionManager* session_manager = UserSessionManager::GetInstance(); |
| DCHECK(session_manager); |
| ime_state_ = session_manager->GetDefaultIMEState(profile); |
| |
| if (user_is_primary_) { |
| g_browser_process->platform_part() |
| ->GetTimezoneResolverManager() |
| ->SetPrimaryUserPrefs(prefs_); |
| } |
| |
| // Initialize preferences to currently saved state. |
| ApplyPreferences(REASON_INITIALIZATION, ""); |
| |
| // Note that |ime_state_| was modified by ApplyPreferences(), and |
| // SetState() is modifying |current_input_method_| (via |
| // PersistUserInputMethod() ). This way SetState() here may be called only |
| // after ApplyPreferences(). |
| input_method_manager_->SetState(ime_state_); |
| |
| input_method_syncer_.reset( |
| new input_method::InputMethodSyncer(prefs, ime_state_)); |
| input_method_syncer_->Initialize(); |
| |
| // If a guest is logged in, initialize the prefs as if this is the first |
| // login. For a regular user this is done in |
| // UserSessionManager::InitProfilePreferences(). |
| if (base::CommandLine::ForCurrentProcess()->HasSwitch( |
| switches::kGuestSession)) |
| session_manager->SetFirstLoginPrefs(profile, std::string(), std::string()); |
| } |
| |
| void Preferences::InitUserPrefsForTesting( |
| sync_preferences::PrefServiceSyncable* prefs, |
| const user_manager::User* user, |
| scoped_refptr<input_method::InputMethodManager::State> ime_state) { |
| user_ = user; |
| ime_state_ = ime_state; |
| |
| if (ime_state.get()) |
| input_method_manager_->SetState(ime_state); |
| |
| InitUserPrefs(prefs); |
| |
| input_method_syncer_.reset( |
| new input_method::InputMethodSyncer(prefs, ime_state_)); |
| input_method_syncer_->Initialize(); |
| } |
| |
| void Preferences::SetInputMethodListForTesting() { |
| SetInputMethodList(); |
| } |
| |
| void Preferences::OnPreferenceChanged(const std::string& pref_name) { |
| ApplyPreferences(REASON_PREF_CHANGED, pref_name); |
| } |
| |
| void Preferences::ApplyPreferences(ApplyReason reason, |
| const std::string& pref_name) { |
| DCHECK(reason != REASON_PREF_CHANGED || !pref_name.empty()); |
| const bool user_is_owner = |
| user_manager::UserManager::Get()->GetOwnerAccountId() == |
| user_->GetAccountId(); |
| const bool user_is_active = user_->is_active(); |
| |
| system::TouchpadSettings touchpad_settings; |
| system::MouseSettings mouse_settings; |
| |
| if (user_is_primary_ && (reason == REASON_INITIALIZATION || |
| pref_name == prefs::kPerformanceTracingEnabled)) { |
| const bool enabled = performance_tracing_enabled_.GetValue(); |
| if (enabled) |
| tracing_manager_ = TracingManager::Create(); |
| else |
| tracing_manager_.reset(); |
| SystemTrayClient::Get()->SetPerformanceTracingIconVisible(enabled); |
| } |
| if (reason != REASON_PREF_CHANGED || pref_name == prefs::kTapToClickEnabled) { |
| const bool enabled = tap_to_click_enabled_.GetValue(); |
| if (user_is_active) |
| touchpad_settings.SetTapToClick(enabled); |
| if (reason == REASON_PREF_CHANGED) |
| UMA_HISTOGRAM_BOOLEAN("Touchpad.TapToClick.Changed", enabled); |
| else if (reason == REASON_INITIALIZATION) |
| UMA_HISTOGRAM_BOOLEAN("Touchpad.TapToClick.Started", enabled); |
| |
| // Save owner preference in local state to use on login screen. |
| if (user_is_owner) { |
| PrefService* prefs = g_browser_process->local_state(); |
| if (prefs->GetBoolean(prefs::kOwnerTapToClickEnabled) != enabled) |
| prefs->SetBoolean(prefs::kOwnerTapToClickEnabled, enabled); |
| } |
| } |
| if (reason != REASON_PREF_CHANGED || |
| pref_name == prefs::kTapDraggingEnabled) { |
| const bool enabled = tap_dragging_enabled_.GetValue(); |
| if (user_is_active) |
| touchpad_settings.SetTapDragging(enabled); |
| if (reason == REASON_PREF_CHANGED) |
| UMA_HISTOGRAM_BOOLEAN("Touchpad.TapDragging.Changed", enabled); |
| else if (reason == REASON_INITIALIZATION) |
| UMA_HISTOGRAM_BOOLEAN("Touchpad.TapDragging.Started", enabled); |
| } |
| if (reason != REASON_PREF_CHANGED || |
| pref_name == prefs::kEnableTouchpadThreeFingerClick) { |
| const bool enabled = three_finger_click_enabled_.GetValue(); |
| if (user_is_active) |
| touchpad_settings.SetThreeFingerClick(enabled); |
| if (reason == REASON_PREF_CHANGED) |
| UMA_HISTOGRAM_BOOLEAN("Touchpad.ThreeFingerClick.Changed", enabled); |
| else if (reason == REASON_INITIALIZATION) |
| UMA_HISTOGRAM_BOOLEAN("Touchpad.ThreeFingerClick.Started", enabled); |
| } |
| if (reason != REASON_PREF_CHANGED || |
| pref_name == prefs::kUnifiedDesktopEnabledByDefault) { |
| const bool enabled = unified_desktop_enabled_by_default_.GetValue(); |
| // TODO: this needs to work in Config::MASH. http://crbug.com/705591. |
| if (ash::Shell::HasInstance() && |
| chromeos::GetAshConfig() != ash::Config::MASH) { |
| ash::Shell::Get()->display_manager()->SetUnifiedDesktopEnabled(enabled); |
| } |
| } |
| if (reason != REASON_PREF_CHANGED || pref_name == prefs::kNaturalScroll) { |
| // Force natural scroll default if we've sync'd and if the cmd line arg is |
| // set. |
| ForceNaturalScrollDefault(); |
| |
| const bool enabled = natural_scroll_.GetValue(); |
| DVLOG(1) << "Natural scroll set to " << enabled; |
| if (user_is_active) |
| touchpad_settings.SetNaturalScroll(enabled); |
| if (reason == REASON_PREF_CHANGED) |
| UMA_HISTOGRAM_BOOLEAN("Touchpad.NaturalScroll.Changed", enabled); |
| else if (reason == REASON_INITIALIZATION) |
| UMA_HISTOGRAM_BOOLEAN("Touchpad.NaturalScroll.Started", enabled); |
| } |
| if (reason != REASON_PREF_CHANGED || pref_name == prefs::kMouseSensitivity) { |
| const int sensitivity = mouse_sensitivity_.GetValue(); |
| if (user_is_active) |
| mouse_settings.SetSensitivity(sensitivity); |
| if (reason == REASON_PREF_CHANGED) { |
| UMA_HISTOGRAM_ENUMERATION("Mouse.PointerSensitivity.Changed", |
| sensitivity, |
| system::kMaxPointerSensitivity + 1); |
| } else if (reason == REASON_INITIALIZATION) { |
| UMA_HISTOGRAM_ENUMERATION("Mouse.PointerSensitivity.Started", |
| sensitivity, |
| system::kMaxPointerSensitivity + 1); |
| } |
| } |
| if (reason != REASON_PREF_CHANGED || |
| pref_name == prefs::kTouchpadSensitivity) { |
| const int sensitivity = touchpad_sensitivity_.GetValue(); |
| if (user_is_active) |
| touchpad_settings.SetSensitivity(sensitivity); |
| if (reason == REASON_PREF_CHANGED) { |
| UMA_HISTOGRAM_ENUMERATION("Touchpad.PointerSensitivity.Changed", |
| sensitivity, |
| system::kMaxPointerSensitivity + 1); |
| } else if (reason == REASON_INITIALIZATION) { |
| UMA_HISTOGRAM_ENUMERATION("Touchpad.PointerSensitivity.Started", |
| sensitivity, |
| system::kMaxPointerSensitivity + 1); |
| } |
| } |
| if (reason != REASON_PREF_CHANGED || |
| pref_name == prefs::kPrimaryMouseButtonRight) { |
| const bool right = primary_mouse_button_right_.GetValue(); |
| if (user_is_active) |
| mouse_settings.SetPrimaryButtonRight(right); |
| if (reason == REASON_PREF_CHANGED) |
| UMA_HISTOGRAM_BOOLEAN("Mouse.PrimaryButtonRight.Changed", right); |
| else if (reason == REASON_INITIALIZATION) |
| UMA_HISTOGRAM_BOOLEAN("Mouse.PrimaryButtonRight.Started", right); |
| // Save owner preference in local state to use on login screen. |
| if (user_is_owner) { |
| PrefService* prefs = g_browser_process->local_state(); |
| if (prefs->GetBoolean(prefs::kOwnerPrimaryMouseButtonRight) != right) |
| prefs->SetBoolean(prefs::kOwnerPrimaryMouseButtonRight, right); |
| } |
| } |
| if (reason != REASON_PREF_CHANGED || |
| pref_name == prefs::kMouseReverseScroll) { |
| const bool enabled = mouse_reverse_scroll_.GetValue(); |
| if (user_is_active) |
| mouse_settings.SetReverseScroll(enabled); |
| if (reason == REASON_PREF_CHANGED) |
| UMA_HISTOGRAM_BOOLEAN("Mouse.ReverseScroll.Changed", enabled); |
| else if (reason == REASON_INITIALIZATION) |
| UMA_HISTOGRAM_BOOLEAN("Mouse.ReverseScroll.Started", enabled); |
| } |
| if (reason != REASON_PREF_CHANGED || |
| pref_name == prefs::kDownloadDefaultDirectory) { |
| const bool default_download_to_drive = drive::util::IsUnderDriveMountPoint( |
| download_default_directory_.GetValue()); |
| if (reason == REASON_PREF_CHANGED) |
| UMA_HISTOGRAM_BOOLEAN( |
| "FileBrowser.DownloadDestination.IsGoogleDrive.Changed", |
| default_download_to_drive); |
| else if (reason == REASON_INITIALIZATION) |
| UMA_HISTOGRAM_BOOLEAN( |
| "FileBrowser.DownloadDestination.IsGoogleDrive.Started", |
| default_download_to_drive); |
| } |
| |
| if (reason != REASON_PREF_CHANGED || |
| pref_name == prefs::kLanguageXkbAutoRepeatEnabled) { |
| if (user_is_active) { |
| const bool enabled = xkb_auto_repeat_enabled_.GetValue(); |
| input_method::InputMethodManager::Get() |
| ->GetImeKeyboard() |
| ->SetAutoRepeatEnabled(enabled); |
| |
| user_manager::known_user::SetBooleanPref( |
| user_->GetAccountId(), prefs::kLanguageXkbAutoRepeatEnabled, enabled); |
| } |
| } |
| if (reason != REASON_PREF_CHANGED || |
| pref_name == prefs::kLanguageXkbAutoRepeatDelay || |
| pref_name == prefs::kLanguageXkbAutoRepeatInterval) { |
| if (user_is_active) |
| UpdateAutoRepeatRate(); |
| } |
| |
| if (reason == REASON_INITIALIZATION) |
| SetInputMethodList(); |
| |
| if (pref_name == prefs::kLanguagePreloadEngines && |
| reason == REASON_PREF_CHANGED) { |
| SetLanguageConfigStringListAsCSV(language_prefs::kGeneralSectionName, |
| language_prefs::kPreloadEnginesConfigName, |
| preload_engines_.GetValue()); |
| } |
| |
| if ((reason == REASON_INITIALIZATION) || |
| (pref_name == prefs::kLanguageEnabledExtensionImes && |
| reason == REASON_PREF_CHANGED)) { |
| std::string value(enabled_extension_imes_.GetValue()); |
| |
| std::vector<std::string> split_values; |
| if (!value.empty()) { |
| split_values = base::SplitString(value, ",", base::TRIM_WHITESPACE, |
| base::SPLIT_WANT_ALL); |
| } |
| ime_state_->SetEnabledExtensionImes(&split_values); |
| } |
| |
| if (pref_name == prefs::kLanguageImeMenuActivated && |
| (reason == REASON_PREF_CHANGED || reason == REASON_ACTIVE_USER_CHANGED) && |
| base::FeatureList::IsEnabled(features::kOptInImeMenu)) { |
| const bool activated = ime_menu_activated_.GetValue(); |
| input_method::InputMethodManager::Get()->ImeMenuActivationChanged( |
| activated); |
| } |
| |
| if (user_is_active) { |
| system::InputDeviceSettings::Get()->UpdateTouchpadSettings( |
| touchpad_settings); |
| system::InputDeviceSettings::Get()->UpdateMouseSettings(mouse_settings); |
| } |
| |
| if (user_is_primary_ && (reason != REASON_PREF_CHANGED || |
| pref_name == prefs::kWakeOnWifiDarkConnect)) { |
| int features = wake_on_wifi_darkconnect_.GetValue() |
| ? WakeOnWifiManager::WAKE_ON_WIFI_DARKCONNECT |
| : WakeOnWifiManager::WAKE_ON_WIFI_NONE; |
| // The flag enables wake on WiFi packet feature but doesn't update a |
| // preference. |
| if (base::CommandLine::ForCurrentProcess()-> |
| HasSwitch(switches::kWakeOnWifiPacket)) { |
| features |= WakeOnWifiManager::WAKE_ON_WIFI_PACKET; |
| } |
| WakeOnWifiManager::Get()->OnPreferenceChanged( |
| static_cast<WakeOnWifiManager::WakeOnWifiFeature>(features)); |
| } |
| |
| if (pref_name == prefs::kUserTimezone && |
| reason != REASON_ACTIVE_USER_CHANGED) { |
| system::UpdateSystemTimezone(ProfileHelper::Get()->GetProfileByUser(user_)); |
| } |
| |
| if ((pref_name == prefs::kResolveTimezoneByGeolocation || |
| pref_name == prefs::kResolveTimezoneByGeolocationMethod) && |
| reason != REASON_ACTIVE_USER_CHANGED) { |
| if (pref_name == prefs::kResolveTimezoneByGeolocationMethod && |
| !prefs_->FindPreference(prefs::kResolveTimezoneByGeolocationMethod) |
| ->IsDefaultValue()) { |
| prefs_->SetBoolean(prefs::kResolveTimezoneByGeolocationMigratedToMethod, |
| true); |
| } |
| if (user_is_owner) { |
| // Policy check is false here, because there is no owner for enterprise. |
| g_browser_process->local_state()->SetInteger( |
| prefs::kResolveDeviceTimezoneByGeolocationMethod, |
| static_cast<int>(system::TimeZoneResolverManager:: |
| GetEffectiveUserTimeZoneResolveMethod( |
| prefs_, false /* check_policy */))); |
| } |
| if (user_is_primary_) { |
| g_browser_process->platform_part() |
| ->GetTimezoneResolverManager() |
| ->UpdateTimezoneResolver(); |
| if (system::TimeZoneResolverManager:: |
| GetEffectiveUserTimeZoneResolveMethod( |
| prefs_, true /* check_policy */) == |
| system::TimeZoneResolverManager::TimeZoneResolveMethod:: |
| DISABLED && |
| reason == REASON_PREF_CHANGED) { |
| // Allow immediate timezone update on Stop + Start. |
| g_browser_process->local_state()->ClearPref( |
| TimeZoneResolver::kLastTimeZoneRefreshTime); |
| } |
| } |
| } |
| |
| if (pref_name == prefs::kUse24HourClock || |
| reason != REASON_ACTIVE_USER_CHANGED) { |
| const bool value = prefs_->GetBoolean(prefs::kUse24HourClock); |
| user_manager::known_user::SetBooleanPref(user_->GetAccountId(), |
| prefs::kUse24HourClock, value); |
| } |
| |
| for (auto* remap_pref : kLanguageRemapPrefs) { |
| if (pref_name == remap_pref || reason != REASON_ACTIVE_USER_CHANGED) { |
| const int value = prefs_->GetInteger(remap_pref); |
| user_manager::known_user::SetIntegerPref(user_->GetAccountId(), |
| remap_pref, value); |
| } |
| } |
| } |
| |
| void Preferences::OnIsSyncingChanged() { |
| DVLOG(1) << "OnIsSyncingChanged"; |
| |
| // By this moment, |prefs| are already synchronized. |
| TryMigrateToResolveTimezoneByGeolocationMethod(prefs_); |
| |
| ForceNaturalScrollDefault(); |
| } |
| |
| void Preferences::ForceNaturalScrollDefault() { |
| DVLOG(1) << "ForceNaturalScrollDefault"; |
| if (base::CommandLine::ForCurrentProcess()->HasSwitch( |
| switches::kNaturalScrollDefault) && |
| prefs_->IsSyncing() && !prefs_->GetUserPrefValue(prefs::kNaturalScroll)) { |
| DVLOG(1) << "Natural scroll forced to true"; |
| natural_scroll_.SetValue(true); |
| UMA_HISTOGRAM_BOOLEAN("Touchpad.NaturalScroll.Forced", true); |
| } |
| } |
| |
| void Preferences::SetLanguageConfigStringListAsCSV(const char* section, |
| const char* name, |
| const std::string& value) { |
| VLOG(1) << "Setting " << name << " to '" << value << "'"; |
| |
| std::vector<std::string> split_values; |
| if (!value.empty()) { |
| split_values = base::SplitString(value, ",", base::TRIM_WHITESPACE, |
| base::SPLIT_WANT_ALL); |
| } |
| |
| // Transfers the xkb id to extension-xkb id. |
| if (input_method_manager_->MigrateInputMethods(&split_values)) |
| preload_engines_.SetValue(base::JoinString(split_values, ",")); |
| |
| if (section == std::string(language_prefs::kGeneralSectionName) && |
| name == std::string(language_prefs::kPreloadEnginesConfigName)) { |
| ime_state_->ReplaceEnabledInputMethods(split_values); |
| return; |
| } |
| } |
| |
| void Preferences::SetInputMethodList() { |
| // When |preload_engines_| are set, InputMethodManager::ChangeInputMethod() |
| // might be called to change the current input method to the first one in the |
| // |preload_engines_| list. This also updates previous/current input method |
| // prefs. That's why GetValue() calls are placed before the |
| // SetLanguageConfigStringListAsCSV() call below. |
| const std::string previous_input_method_id = |
| previous_input_method_.GetValue(); |
| const std::string current_input_method_id = current_input_method_.GetValue(); |
| SetLanguageConfigStringListAsCSV(language_prefs::kGeneralSectionName, |
| language_prefs::kPreloadEnginesConfigName, |
| preload_engines_.GetValue()); |
| |
| // ChangeInputMethod() has to be called AFTER the value of |preload_engines_| |
| // is sent to the InputMethodManager. Otherwise, the ChangeInputMethod request |
| // might be ignored as an invalid input method ID. The ChangeInputMethod() |
| // calls are also necessary to restore the previous/current input method prefs |
| // which could have been modified by the SetLanguageConfigStringListAsCSV call |
| // above to the original state. |
| if (!previous_input_method_id.empty()) |
| ime_state_->ChangeInputMethod(previous_input_method_id, |
| false /* show_message */); |
| if (!current_input_method_id.empty()) |
| ime_state_->ChangeInputMethod(current_input_method_id, |
| false /* show_message */); |
| } |
| |
| void Preferences::UpdateAutoRepeatRate() { |
| input_method::AutoRepeatRate rate; |
| rate.initial_delay_in_ms = xkb_auto_repeat_delay_pref_.GetValue(); |
| rate.repeat_interval_in_ms = xkb_auto_repeat_interval_pref_.GetValue(); |
| DCHECK(rate.initial_delay_in_ms > 0); |
| DCHECK(rate.repeat_interval_in_ms > 0); |
| input_method::InputMethodManager::Get() |
| ->GetImeKeyboard() |
| ->SetAutoRepeatRate(rate); |
| |
| user_manager::known_user::SetIntegerPref(user_->GetAccountId(), |
| prefs::kLanguageXkbAutoRepeatDelay, |
| rate.initial_delay_in_ms); |
| user_manager::known_user::SetIntegerPref( |
| user_->GetAccountId(), prefs::kLanguageXkbAutoRepeatInterval, |
| rate.repeat_interval_in_ms); |
| } |
| |
| void Preferences::ActiveUserChanged(const user_manager::User* active_user) { |
| if (active_user != user_) |
| return; |
| ApplyPreferences(REASON_ACTIVE_USER_CHANGED, ""); |
| } |
| |
| } // namespace chromeos |