1 // Copyright (c) 2013 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/ui/gesture_prefs_observer_factory_aura.h" 6 7 #include <vector> 8 9 #include "base/bind.h" 10 #include "base/bind_helpers.h" 11 #include "base/compiler_specific.h" 12 #include "base/prefs/pref_change_registrar.h" 13 #include "base/prefs/pref_service.h" 14 #include "chrome/browser/chrome_notification_types.h" 15 #include "chrome/browser/profiles/incognito_helpers.h" 16 #include "chrome/browser/profiles/profile.h" 17 #include "chrome/common/pref_names.h" 18 #include "components/keyed_service/content/browser_context_dependency_manager.h" 19 #include "components/pref_registry/pref_registry_syncable.h" 20 #include "content/public/browser/notification_observer.h" 21 #include "content/public/browser/notification_service.h" 22 #include "content/public/browser/overscroll_configuration.h" 23 #include "content/public/common/renderer_preferences.h" 24 #include "ui/events/gestures/gesture_configuration.h" 25 26 using ui::GestureConfiguration; 27 28 namespace { 29 30 struct OverscrollPref { 31 const char* pref_name; 32 content::OverscrollConfig config; 33 }; 34 35 const std::vector<OverscrollPref>& GetOverscrollPrefs() { 36 CR_DEFINE_STATIC_LOCAL(std::vector<OverscrollPref>, overscroll_prefs, ()); 37 if (overscroll_prefs.empty()) { 38 using namespace content; 39 const OverscrollPref kOverscrollPrefs[] = { 40 { prefs::kOverscrollHorizontalThresholdComplete, 41 OVERSCROLL_CONFIG_HORIZ_THRESHOLD_COMPLETE }, 42 { prefs::kOverscrollVerticalThresholdComplete, 43 OVERSCROLL_CONFIG_VERT_THRESHOLD_COMPLETE }, 44 { prefs::kOverscrollMinimumThresholdStart, 45 OVERSCROLL_CONFIG_HORIZ_THRESHOLD_START_TOUCHSCREEN }, 46 { prefs::kOverscrollMinimumThresholdStartTouchpad, 47 OVERSCROLL_CONFIG_HORIZ_THRESHOLD_START_TOUCHPAD }, 48 { prefs::kOverscrollVerticalThresholdStart, 49 OVERSCROLL_CONFIG_VERT_THRESHOLD_START }, 50 { prefs::kOverscrollHorizontalResistThreshold, 51 OVERSCROLL_CONFIG_HORIZ_RESIST_AFTER }, 52 { prefs::kOverscrollVerticalResistThreshold, 53 OVERSCROLL_CONFIG_VERT_RESIST_AFTER }, 54 }; 55 overscroll_prefs.assign(kOverscrollPrefs, 56 kOverscrollPrefs + arraysize(kOverscrollPrefs)); 57 } 58 return overscroll_prefs; 59 } 60 61 // This class manages gesture configuration preferences. 62 class GesturePrefsObserver : public KeyedService { 63 public: 64 explicit GesturePrefsObserver(PrefService* prefs); 65 virtual ~GesturePrefsObserver(); 66 67 // KeyedService implementation. 68 virtual void Shutdown() OVERRIDE; 69 70 private: 71 // Notification callback invoked when browser-side preferences 72 // are updated and need to be pushed into ui::GesturePreferences. 73 void Update(); 74 75 // Notification callback invoked when the fling deacceleration 76 // gesture preferences are changed from chrome://gesture. 77 // Broadcasts the changes all renderers where they are used. 78 void Notify(); 79 80 // Notification helper to push overscroll preferences into 81 // content. 82 void UpdateOverscrollPrefs(); 83 84 PrefChangeRegistrar registrar_; 85 PrefService* prefs_; 86 87 DISALLOW_COPY_AND_ASSIGN(GesturePrefsObserver); 88 }; 89 90 // The list of prefs we want to observe. 91 // Note that this collection of settings should correspond to the settings used 92 // in ui/events/gestures/gesture_configuration.h 93 const char* kPrefsToObserve[] = { 94 prefs::kFlingMaxCancelToDownTimeInMs, 95 prefs::kFlingMaxTapGapTimeInMs, 96 prefs::kTabScrubActivationDelayInMS, 97 prefs::kMaxSeparationForGestureTouchesInPixels, 98 prefs::kSemiLongPressTimeInSeconds, 99 }; 100 101 const char* kPrefsToRemove[] = { 102 "gesture.fling_acceleration_curve_coefficient_0", 103 "gesture.fling_acceleration_curve_coefficient_1", 104 "gesture.fling_acceleration_curve_coefficient_2", 105 "gesture.fling_acceleration_curve_coefficient_3", 106 "flingcurve.touchpad_alpha", 107 "flingcurve.touchpad_beta", 108 "flingcurve.touchpad_gamma", 109 "flingcurve.touchscreen_alpha", 110 "flingcurve.touchscreen_beta", 111 "flingcurve.touchscreen_gamma", 112 }; 113 114 GesturePrefsObserver::GesturePrefsObserver(PrefService* prefs) 115 : prefs_(prefs) { 116 for (size_t i = 0; i < arraysize(kPrefsToRemove); ++i) { 117 if (prefs->FindPreference(kPrefsToRemove[i])) 118 prefs->ClearPref(kPrefsToRemove[i]); 119 } 120 121 registrar_.Init(prefs); 122 registrar_.RemoveAll(); 123 base::Closure callback = base::Bind(&GesturePrefsObserver::Update, 124 base::Unretained(this)); 125 126 base::Closure notify_callback = base::Bind(&GesturePrefsObserver::Notify, 127 base::Unretained(this)); 128 129 for (size_t i = 0; i < arraysize(kPrefsToObserve); ++i) 130 registrar_.Add(kPrefsToObserve[i], callback); 131 132 const std::vector<OverscrollPref>& overscroll_prefs = GetOverscrollPrefs(); 133 for (size_t i = 0; i < overscroll_prefs.size(); ++i) 134 registrar_.Add(overscroll_prefs[i].pref_name, callback); 135 136 Update(); 137 } 138 139 GesturePrefsObserver::~GesturePrefsObserver() {} 140 141 void GesturePrefsObserver::Shutdown() { 142 registrar_.RemoveAll(); 143 } 144 145 void GesturePrefsObserver::Update() { 146 GestureConfiguration::set_fling_max_cancel_to_down_time_in_ms( 147 prefs_->GetInteger(prefs::kFlingMaxCancelToDownTimeInMs)); 148 GestureConfiguration::set_fling_max_tap_gap_time_in_ms( 149 prefs_->GetInteger(prefs::kFlingMaxTapGapTimeInMs)); 150 GestureConfiguration::set_tab_scrub_activation_delay_in_ms( 151 prefs_->GetInteger(prefs::kTabScrubActivationDelayInMS)); 152 GestureConfiguration::set_semi_long_press_time_in_seconds( 153 prefs_->GetDouble(prefs::kSemiLongPressTimeInSeconds)); 154 GestureConfiguration::set_max_separation_for_gesture_touches_in_pixels( 155 prefs_->GetDouble(prefs::kMaxSeparationForGestureTouchesInPixels)); 156 157 UpdateOverscrollPrefs(); 158 } 159 160 void GesturePrefsObserver::UpdateOverscrollPrefs() { 161 const std::vector<OverscrollPref>& overscroll_prefs = GetOverscrollPrefs(); 162 for (size_t i = 0; i < overscroll_prefs.size(); ++i) { 163 content::SetOverscrollConfig(overscroll_prefs[i].config, 164 static_cast<float>(prefs_->GetDouble(overscroll_prefs[i].pref_name))); 165 } 166 } 167 168 void GesturePrefsObserver::Notify() { 169 // Must do a notify to distribute the changes to all renderers. 170 content::NotificationService* service = 171 content::NotificationService::current(); 172 service->Notify(chrome::NOTIFICATION_BROWSER_FLING_CURVE_PARAMETERS_CHANGED, 173 content::Source<GesturePrefsObserver>(this), 174 content::NotificationService::NoDetails()); 175 } 176 177 } // namespace 178 179 // static 180 GesturePrefsObserverFactoryAura* 181 GesturePrefsObserverFactoryAura::GetInstance() { 182 return Singleton<GesturePrefsObserverFactoryAura>::get(); 183 } 184 185 GesturePrefsObserverFactoryAura::GesturePrefsObserverFactoryAura() 186 : BrowserContextKeyedServiceFactory( 187 "GesturePrefsObserverAura", 188 BrowserContextDependencyManager::GetInstance()) {} 189 190 GesturePrefsObserverFactoryAura::~GesturePrefsObserverFactoryAura() {} 191 192 KeyedService* GesturePrefsObserverFactoryAura::BuildServiceInstanceFor( 193 content::BrowserContext* profile) const { 194 return new GesturePrefsObserver(static_cast<Profile*>(profile)->GetPrefs()); 195 } 196 197 void GesturePrefsObserverFactoryAura::RegisterOverscrollPrefs( 198 user_prefs::PrefRegistrySyncable* registry) { 199 const std::vector<OverscrollPref>& overscroll_prefs = GetOverscrollPrefs(); 200 201 for (size_t i = 0; i < overscroll_prefs.size(); ++i) { 202 registry->RegisterDoublePref( 203 overscroll_prefs[i].pref_name, 204 content::GetOverscrollConfig(overscroll_prefs[i].config), 205 user_prefs::PrefRegistrySyncable::UNSYNCABLE_PREF); 206 } 207 } 208 209 void GesturePrefsObserverFactoryAura::RegisterProfilePrefs( 210 user_prefs::PrefRegistrySyncable* registry) { 211 registry->RegisterIntegerPref( 212 prefs::kFlingMaxCancelToDownTimeInMs, 213 GestureConfiguration::fling_max_cancel_to_down_time_in_ms(), 214 user_prefs::PrefRegistrySyncable::UNSYNCABLE_PREF); 215 registry->RegisterIntegerPref( 216 prefs::kFlingMaxTapGapTimeInMs, 217 GestureConfiguration::fling_max_tap_gap_time_in_ms(), 218 user_prefs::PrefRegistrySyncable::UNSYNCABLE_PREF); 219 registry->RegisterIntegerPref( 220 prefs::kTabScrubActivationDelayInMS, 221 GestureConfiguration::tab_scrub_activation_delay_in_ms(), 222 user_prefs::PrefRegistrySyncable::UNSYNCABLE_PREF); 223 registry->RegisterDoublePref( 224 prefs::kSemiLongPressTimeInSeconds, 225 GestureConfiguration::semi_long_press_time_in_seconds(), 226 user_prefs::PrefRegistrySyncable::UNSYNCABLE_PREF); 227 registry->RegisterDoublePref( 228 prefs::kMaxSeparationForGestureTouchesInPixels, 229 GestureConfiguration::max_separation_for_gesture_touches_in_pixels(), 230 user_prefs::PrefRegistrySyncable::UNSYNCABLE_PREF); 231 RegisterOverscrollPrefs(registry); 232 } 233 234 bool 235 GesturePrefsObserverFactoryAura::ServiceIsCreatedWithBrowserContext() const { 236 // Create the observer as soon as the profile is created. 237 return true; 238 } 239 240 content::BrowserContext* 241 GesturePrefsObserverFactoryAura::GetBrowserContextToUse( 242 content::BrowserContext* context) const { 243 // Use same gesture preferences on incognito windows. 244 return chrome::GetBrowserContextRedirectedInIncognito(context); 245 } 246 247 bool GesturePrefsObserverFactoryAura::ServiceIsNULLWhileTesting() const { 248 // Some tests replace the PrefService of the TestingProfile after the 249 // GesturePrefsObserver has been created, which makes Shutdown() 250 // remove the registrar from a non-existent PrefService. 251 return true; 252 } 253