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