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::kFlingCurveTouchscreenAlpha, 62 prefs::kFlingCurveTouchscreenBeta, 63 prefs::kFlingCurveTouchscreenGamma, 64 prefs::kFlingCurveTouchpadAlpha, 65 prefs::kFlingCurveTouchpadBeta, 66 prefs::kFlingCurveTouchpadGamma, 67 }; 68 69 void RevertPreferences(PrefService* prefs, 70 std::map<int, const base::Value*>* vals) { 71 std::map<int, const base::Value*>::const_iterator it; 72 for (it = vals->begin(); it != vals->end(); ++it) { 73 if (!prefs->FindPreference(kWhitelist[it->first])) 74 continue; 75 76 if (!it->second) { 77 prefs->ClearPref(kWhitelist[it->first]); 78 } else { 79 prefs->Set(kWhitelist[it->first], *it->second); 80 delete it->second; 81 } 82 } 83 } 84 85 } // namespace 86 87 SalsaUI::SalsaUI(content::WebUI* web_ui) 88 : content::WebUIController(web_ui) { 89 // Set up the chrome://salsa source. 90 content::WebUIDataSource* html_source = 91 content::WebUIDataSource::Create(chrome::kChromeUISalsaHost); 92 93 // Register callback handlers. 94 web_ui->RegisterMessageCallback( 95 "salsaSetPreferenceValue", 96 base::Bind(&SalsaUI::SetPreferenceValue, 97 base::Unretained(this))); 98 web_ui->RegisterMessageCallback( 99 "salsaBackupPreferenceValue", 100 base::Bind(&SalsaUI::BackupPreferenceValue, 101 base::Unretained(this))); 102 103 // Add required resources. 104 html_source->AddResourcePath("salsa.css", IDR_SALSA_CSS); 105 html_source->AddResourcePath("salsa.js", IDR_SALSA_JS); 106 html_source->SetDefaultResource(IDR_SALSA_HTML); 107 108 Profile* profile = Profile::FromWebUI(web_ui); 109 content::WebUIDataSource::Add(profile, html_source); 110 } 111 112 SalsaUI::~SalsaUI() { 113 std::map<int, const base::Value*>* values_to_revert = 114 new std::map<int, const base::Value*>; 115 values_to_revert->swap(orig_values_); 116 117 Profile* profile = Profile::FromWebUI(web_ui()); 118 PrefService* prefs = profile->GetPrefs(); 119 120 content::BrowserThread::PostTask( 121 content::BrowserThread::UI, 122 FROM_HERE, 123 base::Bind(&RevertPreferences, prefs, base::Owned(values_to_revert)) 124 ); 125 } 126 127 int SalsaUI::WhitelistIndex(const char* key) const { 128 if (!key) 129 return -1; 130 131 int len = arraysize(kWhitelist); 132 for (int i = 0; i < len; ++i) { 133 if (!strcmp(key, kWhitelist[i])) 134 return i; 135 } 136 return -1; 137 } 138 139 void SalsaUI::SetPreferenceValue(const base::ListValue* args) { 140 std::string pref_name; 141 const base::Value* value; 142 if (!args->GetString(0, &pref_name) || !args->Get(1, &value)) 143 return; 144 145 int index = WhitelistIndex(pref_name.c_str()); 146 if (index < 0) 147 return; 148 149 Profile* profile = Profile::FromWebUI(web_ui()); 150 PrefService* prefs = profile->GetPrefs(); 151 const PrefService::Preference* pref = 152 prefs->FindPreference(kWhitelist[index]); 153 154 if (pref->GetType() == value->GetType()) { 155 prefs->Set(kWhitelist[index], *value); 156 } else if (pref->GetType() == base::Value::TYPE_DOUBLE && 157 value->GetType() == base::Value::TYPE_INTEGER) { 158 int int_val; 159 if (!value->GetAsInteger(&int_val)) 160 return; 161 base::FundamentalValue double_val(static_cast<double>(int_val)); 162 prefs->Set(kWhitelist[index], double_val); 163 } 164 } 165 166 void SalsaUI::BackupPreferenceValue(const base::ListValue* args) { 167 std::string pref_name; 168 if (!args->GetString(0, &pref_name)) 169 return; 170 171 int index = WhitelistIndex(pref_name.c_str()); 172 if (index < 0) 173 return; 174 175 Profile* profile = Profile::FromWebUI(web_ui()); 176 PrefService* prefs = profile->GetPrefs(); 177 const PrefService::Preference* pref = 178 prefs->FindPreference(kWhitelist[index]); 179 180 if (!pref) 181 return; 182 183 // Get our own copy of the user defined value or NULL if they are using the 184 // default. You have to make a copy since they'll be used in the destructor 185 // to restore the values and we need to make sure they're still around. 186 orig_values_[index] = 187 pref->IsDefaultValue() ? NULL : pref->GetValue()->DeepCopy(); 188 } 189