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 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