Home | History | Annotate | Download | only in ui
      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