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 // TODO(tdresser): Remove these deprecated prefs in M38. See crbug.com/379912. 31 32 const char kFlingVelocityCap[] = "gesture.fling_velocity_cap"; 33 const char kLongPressTimeInSeconds[] = 34 "gesture.long_press_time_in_seconds"; 35 const char kMaxDistanceBetweenTapsForDoubleTap[] = 36 "gesture.max_distance_between_taps_for_double_tap"; 37 const char kMaxDistanceForTwoFingerTapInPixels[] = 38 "gesture.max_distance_for_two_finger_tap_in_pixels"; 39 const char kMaxSecondsBetweenDoubleClick[] = 40 "gesture.max_seconds_between_double_click"; 41 const char kMaxSwipeDeviationRatio[] = 42 "gesture.max_swipe_deviation_ratio"; 43 const char kMaxTouchDownDurationInSecondsForClick[] = 44 "gesture.max_touch_down_duration_in_seconds_for_click"; 45 const char kMaxTouchMoveInPixelsForClick[] = 46 "gesture.max_touch_move_in_pixels_for_click"; 47 const char kMinDistanceForPinchScrollInPixels[] = 48 "gesture.min_distance_for_pinch_scroll_in_pixels"; 49 const char kMinFlickSpeedSquared[] = 50 "gesture.min_flick_speed_squared"; 51 const char kMinPinchUpdateDistanceInPixels[] = 52 "gesture.min_pinch_update_distance_in_pixels"; 53 const char kMinRailBreakVelocity[] = 54 "gesture.min_rail_break_velocity"; 55 const char kMinScrollDeltaSquared[] = 56 "gesture.min_scroll_delta_squared"; 57 const char kMinSwipeSpeed[] = 58 "gesture.min_swipe_speed"; 59 const char kMinTouchDownDurationInSecondsForClick[] = 60 "gesture.min_touch_down_duration_in_seconds_for_click"; 61 const char kPointsBufferedForVelocity[] = 62 "gesture.points_buffered_for_velocity"; 63 const char kRailBreakProportion[] = 64 "gesture.rail_break_proportion"; 65 const char kRailStartProportion[] = 66 "gesture.rail_start_proportion"; 67 const char kScrollPredictionSeconds[] = 68 "gesture.scroll_prediction_seconds"; 69 const char kShowPressDelayInMS[] = 70 "gesture.show_press_delay_in_ms"; 71 72 struct OverscrollPref { 73 const char* pref_name; 74 content::OverscrollConfig config; 75 }; 76 77 const std::vector<OverscrollPref>& GetOverscrollPrefs() { 78 CR_DEFINE_STATIC_LOCAL(std::vector<OverscrollPref>, overscroll_prefs, ()); 79 if (overscroll_prefs.empty()) { 80 using namespace content; 81 const OverscrollPref kOverscrollPrefs[] = { 82 { prefs::kOverscrollHorizontalThresholdComplete, 83 OVERSCROLL_CONFIG_HORIZ_THRESHOLD_COMPLETE }, 84 { prefs::kOverscrollVerticalThresholdComplete, 85 OVERSCROLL_CONFIG_VERT_THRESHOLD_COMPLETE }, 86 { prefs::kOverscrollMinimumThresholdStart, 87 OVERSCROLL_CONFIG_HORIZ_THRESHOLD_START_TOUCHSCREEN }, 88 { prefs::kOverscrollMinimumThresholdStartTouchpad, 89 OVERSCROLL_CONFIG_HORIZ_THRESHOLD_START_TOUCHPAD }, 90 { prefs::kOverscrollVerticalThresholdStart, 91 OVERSCROLL_CONFIG_VERT_THRESHOLD_START }, 92 { prefs::kOverscrollHorizontalResistThreshold, 93 OVERSCROLL_CONFIG_HORIZ_RESIST_AFTER }, 94 { prefs::kOverscrollVerticalResistThreshold, 95 OVERSCROLL_CONFIG_VERT_RESIST_AFTER }, 96 }; 97 overscroll_prefs.assign(kOverscrollPrefs, 98 kOverscrollPrefs + arraysize(kOverscrollPrefs)); 99 } 100 return overscroll_prefs; 101 } 102 103 // This class manages gesture configuration preferences. 104 class GesturePrefsObserver : public KeyedService { 105 public: 106 explicit GesturePrefsObserver(PrefService* prefs); 107 virtual ~GesturePrefsObserver(); 108 109 // KeyedService implementation. 110 virtual void Shutdown() OVERRIDE; 111 112 private: 113 // Notification callback invoked when browser-side preferences 114 // are updated and need to be pushed into ui::GesturePreferences. 115 void Update(); 116 117 // Notification callback invoked when the fling deacceleration 118 // gesture preferences are changed from chrome://gesture. 119 // Broadcasts the changes all renderers where they are used. 120 void Notify(); 121 122 // Notification helper to push overscroll preferences into 123 // content. 124 void UpdateOverscrollPrefs(); 125 126 PrefChangeRegistrar registrar_; 127 PrefService* prefs_; 128 129 DISALLOW_COPY_AND_ASSIGN(GesturePrefsObserver); 130 }; 131 132 // The list of prefs we want to observe. 133 // Note that this collection of settings should correspond to the settings used 134 // in ui/events/gestures/gesture_configuration.h 135 const char* kPrefsToObserve[] = { 136 prefs::kFlingAccelerationCurveCoefficient0, 137 prefs::kFlingAccelerationCurveCoefficient1, 138 prefs::kFlingAccelerationCurveCoefficient2, 139 prefs::kFlingAccelerationCurveCoefficient3, 140 prefs::kFlingMaxCancelToDownTimeInMs, 141 prefs::kFlingMaxTapGapTimeInMs, 142 prefs::kTabScrubActivationDelayInMS, 143 prefs::kMaxSeparationForGestureTouchesInPixels, 144 prefs::kSemiLongPressTimeInSeconds, 145 }; 146 147 const char* kFlingTouchpadPrefs[] = { 148 prefs::kFlingCurveTouchpadAlpha, 149 prefs::kFlingCurveTouchpadBeta, 150 prefs::kFlingCurveTouchpadGamma 151 }; 152 153 const char* kFlingTouchscreenPrefs[] = { 154 prefs::kFlingCurveTouchscreenAlpha, 155 prefs::kFlingCurveTouchscreenBeta, 156 prefs::kFlingCurveTouchscreenGamma, 157 }; 158 159 const char* kPrefsToRemove[] = { 160 kFlingVelocityCap, 161 kLongPressTimeInSeconds, 162 kMaxDistanceBetweenTapsForDoubleTap, 163 kMaxDistanceForTwoFingerTapInPixels, 164 kMaxSecondsBetweenDoubleClick, 165 kMaxSwipeDeviationRatio, 166 kMaxTouchDownDurationInSecondsForClick, 167 kMaxTouchMoveInPixelsForClick, 168 kMinDistanceForPinchScrollInPixels, 169 kMinFlickSpeedSquared, 170 kMinPinchUpdateDistanceInPixels, 171 kMinRailBreakVelocity, 172 kMinScrollDeltaSquared, 173 kMinSwipeSpeed, 174 kMinTouchDownDurationInSecondsForClick, 175 kPointsBufferedForVelocity, 176 kRailBreakProportion, 177 kRailStartProportion, 178 kScrollPredictionSeconds, 179 kShowPressDelayInMS, 180 }; 181 182 GesturePrefsObserver::GesturePrefsObserver(PrefService* prefs) 183 : prefs_(prefs) { 184 // Clear for migration. 185 for (size_t i = 0; i < arraysize(kPrefsToRemove); ++i) { 186 if (prefs->FindPreference(kPrefsToRemove[i])) 187 prefs->ClearPref(kPrefsToRemove[i]); 188 } 189 190 registrar_.Init(prefs); 191 registrar_.RemoveAll(); 192 base::Closure callback = base::Bind(&GesturePrefsObserver::Update, 193 base::Unretained(this)); 194 195 base::Closure notify_callback = base::Bind(&GesturePrefsObserver::Notify, 196 base::Unretained(this)); 197 198 for (size_t i = 0; i < arraysize(kPrefsToObserve); ++i) 199 registrar_.Add(kPrefsToObserve[i], callback); 200 201 const std::vector<OverscrollPref>& overscroll_prefs = GetOverscrollPrefs(); 202 for (size_t i = 0; i < overscroll_prefs.size(); ++i) 203 registrar_.Add(overscroll_prefs[i].pref_name, callback); 204 205 for (size_t i = 0; i < arraysize(kFlingTouchpadPrefs); ++i) 206 registrar_.Add(kFlingTouchpadPrefs[i], notify_callback); 207 for (size_t i = 0; i < arraysize(kFlingTouchscreenPrefs); ++i) 208 registrar_.Add(kFlingTouchscreenPrefs[i], notify_callback); 209 210 Update(); 211 } 212 213 GesturePrefsObserver::~GesturePrefsObserver() {} 214 215 void GesturePrefsObserver::Shutdown() { 216 registrar_.RemoveAll(); 217 } 218 219 void GesturePrefsObserver::Update() { 220 GestureConfiguration::set_fling_acceleration_curve_coefficients(0, 221 prefs_->GetDouble(prefs::kFlingAccelerationCurveCoefficient0)); 222 GestureConfiguration::set_fling_acceleration_curve_coefficients(1, 223 prefs_->GetDouble(prefs::kFlingAccelerationCurveCoefficient1)); 224 GestureConfiguration::set_fling_acceleration_curve_coefficients(2, 225 prefs_->GetDouble(prefs::kFlingAccelerationCurveCoefficient2)); 226 GestureConfiguration::set_fling_acceleration_curve_coefficients(3, 227 prefs_->GetDouble(prefs::kFlingAccelerationCurveCoefficient3)); 228 GestureConfiguration::set_fling_max_cancel_to_down_time_in_ms( 229 prefs_->GetInteger(prefs::kFlingMaxCancelToDownTimeInMs)); 230 GestureConfiguration::set_fling_max_tap_gap_time_in_ms( 231 prefs_->GetInteger(prefs::kFlingMaxTapGapTimeInMs)); 232 GestureConfiguration::set_tab_scrub_activation_delay_in_ms( 233 prefs_->GetInteger(prefs::kTabScrubActivationDelayInMS)); 234 GestureConfiguration::set_semi_long_press_time_in_seconds( 235 prefs_->GetDouble( 236 prefs::kSemiLongPressTimeInSeconds)); 237 GestureConfiguration::set_max_separation_for_gesture_touches_in_pixels( 238 prefs_->GetDouble( 239 prefs::kMaxSeparationForGestureTouchesInPixels)); 240 241 UpdateOverscrollPrefs(); 242 } 243 244 void GesturePrefsObserver::UpdateOverscrollPrefs() { 245 const std::vector<OverscrollPref>& overscroll_prefs = GetOverscrollPrefs(); 246 for (size_t i = 0; i < overscroll_prefs.size(); ++i) { 247 content::SetOverscrollConfig(overscroll_prefs[i].config, 248 static_cast<float>(prefs_->GetDouble(overscroll_prefs[i].pref_name))); 249 } 250 } 251 252 void GesturePrefsObserver::Notify() { 253 // Must do a notify to distribute the changes to all renderers. 254 content::NotificationService* service = 255 content::NotificationService::current(); 256 service->Notify(chrome::NOTIFICATION_BROWSER_FLING_CURVE_PARAMETERS_CHANGED, 257 content::Source<GesturePrefsObserver>(this), 258 content::NotificationService::NoDetails()); 259 } 260 261 } // namespace 262 263 // static 264 GesturePrefsObserverFactoryAura* 265 GesturePrefsObserverFactoryAura::GetInstance() { 266 return Singleton<GesturePrefsObserverFactoryAura>::get(); 267 } 268 269 GesturePrefsObserverFactoryAura::GesturePrefsObserverFactoryAura() 270 : BrowserContextKeyedServiceFactory( 271 "GesturePrefsObserverAura", 272 BrowserContextDependencyManager::GetInstance()) {} 273 274 GesturePrefsObserverFactoryAura::~GesturePrefsObserverFactoryAura() {} 275 276 KeyedService* GesturePrefsObserverFactoryAura::BuildServiceInstanceFor( 277 content::BrowserContext* profile) const { 278 return new GesturePrefsObserver(static_cast<Profile*>(profile)->GetPrefs()); 279 } 280 281 void GesturePrefsObserverFactoryAura::RegisterOverscrollPrefs( 282 user_prefs::PrefRegistrySyncable* registry) { 283 const std::vector<OverscrollPref>& overscroll_prefs = GetOverscrollPrefs(); 284 285 for (size_t i = 0; i < overscroll_prefs.size(); ++i) { 286 registry->RegisterDoublePref( 287 overscroll_prefs[i].pref_name, 288 content::GetOverscrollConfig(overscroll_prefs[i].config), 289 user_prefs::PrefRegistrySyncable::UNSYNCABLE_PREF); 290 } 291 } 292 293 void GesturePrefsObserverFactoryAura::RegisterFlingCurveParameters( 294 user_prefs::PrefRegistrySyncable* registry) { 295 content::RendererPreferences def_prefs; 296 297 for (size_t i = 0; i < arraysize(kFlingTouchpadPrefs); i++) 298 registry->RegisterDoublePref( 299 kFlingTouchpadPrefs[i], 300 def_prefs.touchpad_fling_profile[i], 301 user_prefs::PrefRegistrySyncable::UNSYNCABLE_PREF); 302 303 for (size_t i = 0; i < arraysize(kFlingTouchscreenPrefs); i++) 304 registry->RegisterDoublePref( 305 kFlingTouchscreenPrefs[i], 306 def_prefs.touchscreen_fling_profile[i], 307 user_prefs::PrefRegistrySyncable::UNSYNCABLE_PREF); 308 } 309 310 void GesturePrefsObserverFactoryAura::RegisterProfilePrefs( 311 user_prefs::PrefRegistrySyncable* registry) { 312 registry->RegisterDoublePref( 313 prefs::kFlingAccelerationCurveCoefficient0, 314 GestureConfiguration::fling_acceleration_curve_coefficients(0), 315 user_prefs::PrefRegistrySyncable::UNSYNCABLE_PREF); 316 registry->RegisterDoublePref( 317 prefs::kFlingAccelerationCurveCoefficient1, 318 GestureConfiguration::fling_acceleration_curve_coefficients(1), 319 user_prefs::PrefRegistrySyncable::UNSYNCABLE_PREF); 320 registry->RegisterDoublePref( 321 prefs::kFlingAccelerationCurveCoefficient2, 322 GestureConfiguration::fling_acceleration_curve_coefficients(2), 323 user_prefs::PrefRegistrySyncable::UNSYNCABLE_PREF); 324 registry->RegisterDoublePref( 325 prefs::kFlingAccelerationCurveCoefficient3, 326 GestureConfiguration::fling_acceleration_curve_coefficients(3), 327 user_prefs::PrefRegistrySyncable::UNSYNCABLE_PREF); 328 registry->RegisterIntegerPref( 329 prefs::kFlingMaxCancelToDownTimeInMs, 330 GestureConfiguration::fling_max_cancel_to_down_time_in_ms(), 331 user_prefs::PrefRegistrySyncable::UNSYNCABLE_PREF); 332 registry->RegisterIntegerPref( 333 prefs::kFlingMaxTapGapTimeInMs, 334 GestureConfiguration::fling_max_tap_gap_time_in_ms(), 335 user_prefs::PrefRegistrySyncable::UNSYNCABLE_PREF); 336 registry->RegisterIntegerPref( 337 prefs::kTabScrubActivationDelayInMS, 338 GestureConfiguration::tab_scrub_activation_delay_in_ms(), 339 user_prefs::PrefRegistrySyncable::UNSYNCABLE_PREF); 340 registry->RegisterDoublePref( 341 prefs::kSemiLongPressTimeInSeconds, 342 GestureConfiguration::semi_long_press_time_in_seconds(), 343 user_prefs::PrefRegistrySyncable::UNSYNCABLE_PREF); 344 registry->RegisterDoublePref( 345 prefs::kMaxSeparationForGestureTouchesInPixels, 346 GestureConfiguration::max_separation_for_gesture_touches_in_pixels(), 347 user_prefs::PrefRegistrySyncable::UNSYNCABLE_PREF); 348 RegisterOverscrollPrefs(registry); 349 RegisterFlingCurveParameters(registry); 350 } 351 352 bool 353 GesturePrefsObserverFactoryAura::ServiceIsCreatedWithBrowserContext() const { 354 // Create the observer as soon as the profile is created. 355 return true; 356 } 357 358 content::BrowserContext* 359 GesturePrefsObserverFactoryAura::GetBrowserContextToUse( 360 content::BrowserContext* context) const { 361 // Use same gesture preferences on incognito windows. 362 return chrome::GetBrowserContextRedirectedInIncognito(context); 363 } 364 365 bool GesturePrefsObserverFactoryAura::ServiceIsNULLWhileTesting() const { 366 // Some tests replace the PrefService of the TestingProfile after the 367 // GesturePrefsObserver has been created, which makes Shutdown() 368 // remove the registrar from a non-existent PrefService. 369 return true; 370 } 371