Home | History | Annotate | Download | only in chromeos
      1 // Copyright 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/webui/chromeos/salsa_ui.h"
      6 
      7 #include "base/bind.h"
      8 #include "base/memory/scoped_ptr.h"
      9 #include "base/prefs/pref_service.h"
     10 #include "base/values.h"
     11 #include "chrome/browser/browser_process.h"
     12 #include "chrome/browser/profiles/profile.h"
     13 #include "chrome/common/pref_names.h"
     14 #include "chrome/common/url_constants.h"
     15 #include "content/public/browser/browser_thread.h"
     16 #include "content/public/browser/web_ui.h"
     17 #include "content/public/browser/web_ui_data_source.h"
     18 #include "grit/browser_resources.h"
     19 
     20 // Whitelist of which preferences are possible targets for Salsa treatments.
     21 // If new preferences are added and they are to be used in an experiment, then
     22 // they must be added to this list as well to keep chrome://salsa from
     23 // changing arbitrary values.
     24 
     25 namespace {
     26 
     27 const char* kWhitelist[] = {
     28   prefs::kFlingMaxCancelToDownTimeInMs,
     29   prefs::kFlingMaxTapGapTimeInMs,
     30   prefs::kLongPressTimeInSeconds,
     31   prefs::kLongPressTimeInSeconds,
     32   prefs::kMaxSecondsBetweenDoubleClick,
     33   prefs::kMaxSeparationForGestureTouchesInPixels,
     34   prefs::kMaxSwipeDeviationRatio,
     35   prefs::kMaxTouchDownDurationInSecondsForClick,
     36   prefs::kMaxTouchMoveInPixelsForClick,
     37   prefs::kMaxDistanceBetweenTapsForDoubleTap,
     38   prefs::kMaxDistanceForTwoFingerTapInPixels,
     39   prefs::kMinDistanceForPinchScrollInPixels,
     40   prefs::kMinFlickSpeedSquared,
     41   prefs::kMinPinchUpdateDistanceInPixels,
     42   prefs::kMinRailBreakVelocity,
     43   prefs::kMinScrollDeltaSquared,
     44   prefs::kMinSwipeSpeed,
     45   prefs::kMinTouchDownDurationInSecondsForClick,
     46   prefs::kPointsBufferedForVelocity,
     47   prefs::kRailBreakProportion,
     48   prefs::kRailStartProportion,
     49   prefs::kFlingAccelerationCurveCoefficient0,
     50   prefs::kFlingAccelerationCurveCoefficient1,
     51   prefs::kFlingAccelerationCurveCoefficient2,
     52   prefs::kFlingAccelerationCurveCoefficient3,
     53   prefs::kFlingVelocityCap,
     54   prefs::kTabScrubActivationDelayInMS,
     55   prefs::kOverscrollHorizontalThresholdComplete,
     56   prefs::kOverscrollVerticalThresholdComplete,
     57   prefs::kOverscrollMinimumThresholdStart,
     58   prefs::kOverscrollVerticalThresholdStart,
     59   prefs::kOverscrollHorizontalResistThreshold,
     60   prefs::kOverscrollVerticalResistThreshold,
     61   prefs::kImmersiveModeRevealDelayMs,
     62   prefs::kImmersiveModeRevealXThresholdPixels,
     63   prefs::kFlingCurveTouchscreenAlpha,
     64   prefs::kFlingCurveTouchscreenBeta,
     65   prefs::kFlingCurveTouchscreenGamma,
     66   prefs::kFlingCurveTouchpadAlpha,
     67   prefs::kFlingCurveTouchpadBeta,
     68   prefs::kFlingCurveTouchpadGamma,
     69 };
     70 
     71 void RevertPreferences(PrefService* prefs,
     72                        std::map<int, const base::Value*>* vals) {
     73   std::map<int, const base::Value*>::const_iterator it;
     74   for (it = vals->begin(); it != vals->end(); ++it) {
     75     if (!prefs->FindPreference(kWhitelist[it->first]))
     76       continue;
     77 
     78     if (!it->second) {
     79       prefs->ClearPref(kWhitelist[it->first]);
     80     } else {
     81       prefs->Set(kWhitelist[it->first], *it->second);
     82       delete it->second;
     83     }
     84   }
     85 }
     86 
     87 } // namespace
     88 
     89 SalsaUI::SalsaUI(content::WebUI* web_ui)
     90     : content::WebUIController(web_ui) {
     91   // Set up the chrome://salsa source.
     92   content::WebUIDataSource* html_source =
     93       content::WebUIDataSource::Create(chrome::kChromeUISalsaHost);
     94 
     95   // Register callback handlers.
     96   web_ui->RegisterMessageCallback(
     97       "salsaSetPreferenceValue",
     98       base::Bind(&SalsaUI::SetPreferenceValue,
     99                  base::Unretained(this)));
    100   web_ui->RegisterMessageCallback(
    101       "salsaBackupPreferenceValue",
    102       base::Bind(&SalsaUI::BackupPreferenceValue,
    103                  base::Unretained(this)));
    104 
    105   // Add required resources.
    106   html_source->AddResourcePath("salsa.css", IDR_SALSA_CSS);
    107   html_source->AddResourcePath("salsa.js", IDR_SALSA_JS);
    108   html_source->SetDefaultResource(IDR_SALSA_HTML);
    109 
    110   Profile* profile = Profile::FromWebUI(web_ui);
    111   content::WebUIDataSource::Add(profile, html_source);
    112 }
    113 
    114 SalsaUI::~SalsaUI() {
    115   std::map<int, const base::Value*>* values_to_revert =
    116       new std::map<int, const base::Value*>;
    117   values_to_revert->swap(orig_values_);
    118 
    119   Profile* profile = Profile::FromWebUI(web_ui());
    120   PrefService* prefs = profile->GetPrefs();
    121 
    122   content::BrowserThread::PostTask(
    123       content::BrowserThread::UI,
    124       FROM_HERE,
    125       base::Bind(&RevertPreferences, prefs, base::Owned(values_to_revert))
    126     );
    127 }
    128 
    129 int SalsaUI::WhitelistIndex(const char* key) const {
    130   if (!key)
    131     return -1;
    132 
    133   int len = arraysize(kWhitelist);
    134   for (int i = 0; i < len; ++i) {
    135     if (!strcmp(key, kWhitelist[i]))
    136       return i;
    137   }
    138   return -1;
    139 }
    140 
    141 void SalsaUI::SetPreferenceValue(const base::ListValue* args) {
    142   std::string pref_name;
    143   const base::Value* value;
    144   if (!args->GetString(0, &pref_name) || !args->Get(1, &value))
    145     return;
    146 
    147   int index = WhitelistIndex(pref_name.c_str());
    148   if (index < 0)
    149     return;
    150 
    151   Profile* profile = Profile::FromWebUI(web_ui());
    152   PrefService* prefs = profile->GetPrefs();
    153   const PrefService::Preference* pref =
    154       prefs->FindPreference(kWhitelist[index]);
    155 
    156   if (pref->GetType() == value->GetType()) {
    157     prefs->Set(kWhitelist[index], *value);
    158   } else if (pref->GetType() == base::Value::TYPE_DOUBLE &&
    159              value->GetType() == base::Value::TYPE_INTEGER) {
    160     int int_val;
    161     if (!value->GetAsInteger(&int_val))
    162       return;
    163     base::FundamentalValue double_val(static_cast<double>(int_val));
    164     prefs->Set(kWhitelist[index], double_val);
    165   }
    166 }
    167 
    168 void SalsaUI::BackupPreferenceValue(const base::ListValue* args) {
    169   std::string pref_name;
    170   if (!args->GetString(0, &pref_name))
    171     return;
    172 
    173   int index = WhitelistIndex(pref_name.c_str());
    174   if (index < 0)
    175     return;
    176 
    177   Profile* profile = Profile::FromWebUI(web_ui());
    178   PrefService* prefs = profile->GetPrefs();
    179   const PrefService::Preference* pref =
    180       prefs->FindPreference(kWhitelist[index]);
    181 
    182   if (!pref)
    183     return;
    184 
    185   // Get our own copy of the user defined value or NULL if they are using the
    186   // default. You have to make a copy since they'll be used in the destructor
    187   // to restore the values and we need to make sure they're still around.
    188   orig_values_[index] =
    189       pref->IsDefaultValue() ? NULL : pref->GetValue()->DeepCopy();
    190 }
    191