Disable TabDragController tests that fail with a real compositor.
[chromium-blink-merge.git] / chrome / browser / ui / webui / options / core_options_handler.cc
blob5ce25c562f691b8e235a86d433437cff9aad167e
1 // Copyright (c) 2012 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.
5 #include "chrome/browser/ui/webui/options/core_options_handler.h"
7 #include "base/bind.h"
8 #include "base/bind_helpers.h"
9 #include "base/json/json_reader.h"
10 #include "base/memory/scoped_ptr.h"
11 #include "base/strings/string16.h"
12 #include "base/strings/string_number_conversions.h"
13 #include "base/strings/utf_string_conversions.h"
14 #include "base/values.h"
15 #include "chrome/browser/browser_process.h"
16 #include "chrome/browser/chrome_notification_types.h"
17 #include "chrome/browser/extensions/extension_pref_value_map.h"
18 #include "chrome/browser/extensions/extension_pref_value_map_factory.h"
19 #include "chrome/browser/extensions/extension_service.h"
20 #include "chrome/browser/extensions/extension_system.h"
21 #include "chrome/browser/profiles/profile.h"
22 #include "chrome/browser/ui/options/options_util.h"
23 #include "chrome/common/net/url_fixer_upper.h"
24 #include "chrome/common/pref_names.h"
25 #include "chrome/common/url_constants.h"
26 #include "content/public/browser/notification_details.h"
27 #include "content/public/browser/notification_types.h"
28 #include "content/public/browser/user_metrics.h"
29 #include "content/public/browser/web_ui.h"
30 #include "extensions/common/extension.h"
31 #include "grit/chromium_strings.h"
32 #include "grit/generated_resources.h"
33 #include "grit/locale_settings.h"
34 #include "grit/theme_resources.h"
35 #include "ui/base/l10n/l10n_util.h"
36 #include "url/gurl.h"
38 using base::UserMetricsAction;
40 namespace options {
42 namespace {
44 // Only allow changes to the metrics reporting checkbox if we were succesfully
45 // able to change the service.
46 bool AllowMetricsReportingChange(const base::Value* to_value) {
47 bool enable;
48 if (!to_value->GetAsBoolean(&enable)) {
49 NOTREACHED();
50 return false;
53 return enable == OptionsUtil::ResolveMetricsReportingEnabled(enable);
56 } // namespace
58 CoreOptionsHandler::CoreOptionsHandler()
59 : handlers_host_(NULL) {
62 CoreOptionsHandler::~CoreOptionsHandler() {}
64 void CoreOptionsHandler::InitializeHandler() {
65 Profile* profile = Profile::FromWebUI(web_ui());
67 plugin_status_pref_setter_.Init(
68 profile,
69 base::Bind(&CoreOptionsHandler::OnPreferenceChanged,
70 base::Unretained(this),
71 profile->GetPrefs()));
73 pref_change_filters_[prefs::kMetricsReportingEnabled] =
74 base::Bind(&AllowMetricsReportingChange);
77 void CoreOptionsHandler::InitializePage() {
78 UpdateClearPluginLSOData();
79 UpdatePepperFlashSettingsEnabled();
82 void CoreOptionsHandler::GetLocalizedValues(
83 base::DictionaryValue* localized_strings) {
84 GetStaticLocalizedValues(localized_strings);
87 void CoreOptionsHandler::GetStaticLocalizedValues(
88 base::DictionaryValue* localized_strings) {
89 DCHECK(localized_strings);
90 // Main
91 localized_strings->SetString("optionsPageTitle",
92 l10n_util::GetStringUTF16(IDS_SETTINGS_TITLE));
94 // Controlled settings bubble.
95 localized_strings->SetString("controlledSettingPolicy",
96 l10n_util::GetStringUTF16(IDS_OPTIONS_CONTROLLED_SETTING_POLICY));
97 localized_strings->SetString("controlledSettingExtension",
98 l10n_util::GetStringUTF16(IDS_OPTIONS_CONTROLLED_SETTING_EXTENSION));
99 localized_strings->SetString("controlledSettingExtensionWithName",
100 l10n_util::GetStringUTF16(
101 IDS_OPTIONS_CONTROLLED_SETTING_EXTENSION_WITH_NAME));
102 localized_strings->SetString("controlledSettingManageExtensions",
103 l10n_util::GetStringUTF16(
104 IDS_OPTIONS_CONTROLLED_SETTING_MANAGE_EXTENSIONS));
105 localized_strings->SetString("controlledSettingDisableExtension",
106 l10n_util::GetStringUTF16(IDS_EXTENSIONS_DISABLE));
107 localized_strings->SetString("controlledSettingRecommended",
108 l10n_util::GetStringUTF16(IDS_OPTIONS_CONTROLLED_SETTING_RECOMMENDED));
109 localized_strings->SetString("controlledSettingHasRecommendation",
110 l10n_util::GetStringUTF16(
111 IDS_OPTIONS_CONTROLLED_SETTING_HAS_RECOMMENDATION));
112 localized_strings->SetString("controlledSettingFollowRecommendation",
113 l10n_util::GetStringUTF16(
114 IDS_OPTIONS_CONTROLLED_SETTING_FOLLOW_RECOMMENDATION));
115 localized_strings->SetString("controlledSettingsPolicy",
116 l10n_util::GetStringUTF16(IDS_OPTIONS_CONTROLLED_SETTINGS_POLICY));
117 localized_strings->SetString("controlledSettingsExtension",
118 l10n_util::GetStringUTF16(IDS_OPTIONS_CONTROLLED_SETTINGS_EXTENSION));
119 localized_strings->SetString("controlledSettingsExtensionWithName",
120 l10n_util::GetStringUTF16(
121 IDS_OPTIONS_CONTROLLED_SETTINGS_EXTENSION_WITH_NAME));
123 // Search
124 RegisterTitle(localized_strings, "searchPage", IDS_OPTIONS_SEARCH_PAGE_TITLE);
125 localized_strings->SetString("searchPlaceholder",
126 l10n_util::GetStringUTF16(IDS_OPTIONS_SEARCH_PLACEHOLDER));
127 localized_strings->SetString("searchPageNoMatches",
128 l10n_util::GetStringUTF16(IDS_OPTIONS_SEARCH_PAGE_NO_MATCHES));
129 localized_strings->SetString("searchPageHelpLabel",
130 l10n_util::GetStringUTF16(IDS_OPTIONS_SEARCH_PAGE_HELP_LABEL));
131 localized_strings->SetString("searchPageHelpTitle",
132 l10n_util::GetStringFUTF16(IDS_OPTIONS_SEARCH_PAGE_HELP_TITLE,
133 l10n_util::GetStringUTF16(IDS_PRODUCT_NAME)));
134 localized_strings->SetString("searchPageHelpURL",
135 chrome::kSettingsSearchHelpURL);
137 // Common
138 localized_strings->SetString("ok",
139 l10n_util::GetStringUTF16(IDS_OK));
140 localized_strings->SetString("cancel",
141 l10n_util::GetStringUTF16(IDS_CANCEL));
142 localized_strings->SetString("learnMore",
143 l10n_util::GetStringUTF16(IDS_LEARN_MORE));
144 localized_strings->SetString("close",
145 l10n_util::GetStringUTF16(IDS_CLOSE));
146 localized_strings->SetString("done",
147 l10n_util::GetStringUTF16(IDS_DONE));
150 void CoreOptionsHandler::Uninitialize() {
151 std::string last_pref;
152 for (PreferenceCallbackMap::const_iterator iter = pref_callback_map_.begin();
153 iter != pref_callback_map_.end();
154 ++iter) {
155 if (last_pref != iter->first) {
156 StopObservingPref(iter->first);
157 last_pref = iter->first;
162 void CoreOptionsHandler::OnPreferenceChanged(PrefService* service,
163 const std::string& pref_name) {
164 if (pref_name == prefs::kClearPluginLSODataEnabled) {
165 // This preference is stored in Local State, not in the user preferences.
166 UpdateClearPluginLSOData();
167 return;
169 if (pref_name == prefs::kPepperFlashSettingsEnabled) {
170 UpdatePepperFlashSettingsEnabled();
171 return;
173 NotifyPrefChanged(pref_name, std::string());
176 void CoreOptionsHandler::RegisterMessages() {
177 registrar_.Init(Profile::FromWebUI(web_ui())->GetPrefs());
178 local_state_registrar_.Init(g_browser_process->local_state());
180 web_ui()->RegisterMessageCallback("coreOptionsInitialize",
181 base::Bind(&CoreOptionsHandler::HandleInitialize,
182 base::Unretained(this)));
183 web_ui()->RegisterMessageCallback("fetchPrefs",
184 base::Bind(&CoreOptionsHandler::HandleFetchPrefs,
185 base::Unretained(this)));
186 web_ui()->RegisterMessageCallback("observePrefs",
187 base::Bind(&CoreOptionsHandler::HandleObservePrefs,
188 base::Unretained(this)));
189 web_ui()->RegisterMessageCallback("setBooleanPref",
190 base::Bind(&CoreOptionsHandler::HandleSetBooleanPref,
191 base::Unretained(this)));
192 web_ui()->RegisterMessageCallback("setIntegerPref",
193 base::Bind(&CoreOptionsHandler::HandleSetIntegerPref,
194 base::Unretained(this)));
195 web_ui()->RegisterMessageCallback("setDoublePref",
196 base::Bind(&CoreOptionsHandler::HandleSetDoublePref,
197 base::Unretained(this)));
198 web_ui()->RegisterMessageCallback("setStringPref",
199 base::Bind(&CoreOptionsHandler::HandleSetStringPref,
200 base::Unretained(this)));
201 web_ui()->RegisterMessageCallback("setURLPref",
202 base::Bind(&CoreOptionsHandler::HandleSetURLPref,
203 base::Unretained(this)));
204 web_ui()->RegisterMessageCallback("setListPref",
205 base::Bind(&CoreOptionsHandler::HandleSetListPref,
206 base::Unretained(this)));
207 web_ui()->RegisterMessageCallback("clearPref",
208 base::Bind(&CoreOptionsHandler::HandleClearPref,
209 base::Unretained(this)));
210 web_ui()->RegisterMessageCallback("coreOptionsUserMetricsAction",
211 base::Bind(&CoreOptionsHandler::HandleUserMetricsAction,
212 base::Unretained(this)));
213 web_ui()->RegisterMessageCallback("disableExtension",
214 base::Bind(&CoreOptionsHandler::HandleDisableExtension,
215 base::Unretained(this)));
218 void CoreOptionsHandler::HandleInitialize(const base::ListValue* args) {
219 DCHECK(handlers_host_);
220 handlers_host_->InitializeHandlers();
223 base::Value* CoreOptionsHandler::FetchPref(const std::string& pref_name) {
224 return CreateValueForPref(pref_name, std::string());
227 void CoreOptionsHandler::ObservePref(const std::string& pref_name) {
228 if (g_browser_process->local_state()->FindPreference(pref_name.c_str())) {
229 local_state_registrar_.Add(
230 pref_name.c_str(),
231 base::Bind(&CoreOptionsHandler::OnPreferenceChanged,
232 base::Unretained(this),
233 local_state_registrar_.prefs()));
235 // TODO(pneubeck): change this to if/else once kProxy is only used as a user
236 // pref. Currently, it is both a user and a local state pref.
237 if (Profile::FromWebUI(web_ui())->GetPrefs()->FindPreference(
238 pref_name.c_str())) {
239 registrar_.Add(
240 pref_name.c_str(),
241 base::Bind(&CoreOptionsHandler::OnPreferenceChanged,
242 base::Unretained(this),
243 registrar_.prefs()));
247 void CoreOptionsHandler::StopObservingPref(const std::string& pref_name) {
248 if (g_browser_process->local_state()->FindPreference(pref_name.c_str()))
249 local_state_registrar_.Remove(pref_name.c_str());
250 else
251 registrar_.Remove(pref_name.c_str());
254 void CoreOptionsHandler::SetPref(const std::string& pref_name,
255 const base::Value* value,
256 const std::string& metric) {
257 PrefService* pref_service = FindServiceForPref(pref_name);
258 PrefChangeFilterMap::iterator iter = pref_change_filters_.find(pref_name);
259 if (iter != pref_change_filters_.end()) {
260 // Also check if the pref is user modifiable (don't even try to run the
261 // filter function if the user is not allowed to change the pref).
262 const PrefService::Preference* pref =
263 pref_service->FindPreference(pref_name.c_str());
264 if ((pref && !pref->IsUserModifiable()) || !iter->second.Run(value)) {
265 // Reject the change; remind the page of the true value.
266 NotifyPrefChanged(pref_name, std::string());
267 return;
271 switch (value->GetType()) {
272 case base::Value::TYPE_BOOLEAN:
273 case base::Value::TYPE_INTEGER:
274 case base::Value::TYPE_DOUBLE:
275 case base::Value::TYPE_STRING:
276 case base::Value::TYPE_LIST:
277 pref_service->Set(pref_name.c_str(), *value);
278 break;
280 default:
281 NOTREACHED();
282 return;
285 ProcessUserMetric(value, metric);
288 void CoreOptionsHandler::ClearPref(const std::string& pref_name,
289 const std::string& metric) {
290 PrefService* pref_service = FindServiceForPref(pref_name);
291 pref_service->ClearPref(pref_name.c_str());
293 if (!metric.empty())
294 content::RecordComputedAction(metric);
297 void CoreOptionsHandler::ProcessUserMetric(const base::Value* value,
298 const std::string& metric) {
299 if (metric.empty())
300 return;
302 std::string metric_string = metric;
303 if (value->IsType(base::Value::TYPE_BOOLEAN)) {
304 bool bool_value;
305 CHECK(value->GetAsBoolean(&bool_value));
306 metric_string += bool_value ? "_Enable" : "_Disable";
309 content::RecordComputedAction(metric_string);
312 void CoreOptionsHandler::NotifyPrefChanged(
313 const std::string& pref_name,
314 const std::string& controlling_pref_name) {
315 scoped_ptr<base::Value> value(
316 CreateValueForPref(pref_name, controlling_pref_name));
317 DispatchPrefChangeNotification(pref_name, value.Pass());
320 void CoreOptionsHandler::DispatchPrefChangeNotification(
321 const std::string& name,
322 scoped_ptr<base::Value> value) {
323 std::pair<PreferenceCallbackMap::const_iterator,
324 PreferenceCallbackMap::const_iterator> range =
325 pref_callback_map_.equal_range(name);
326 base::ListValue result_value;
327 result_value.Append(new base::StringValue(name.c_str()));
328 result_value.Append(value.release());
329 for (PreferenceCallbackMap::const_iterator iter = range.first;
330 iter != range.second; ++iter) {
331 const std::string& callback_function = iter->second;
332 web_ui()->CallJavascriptFunction(callback_function, result_value);
336 base::Value* CoreOptionsHandler::CreateValueForPref(
337 const std::string& pref_name,
338 const std::string& controlling_pref_name) {
339 const PrefService* pref_service = FindServiceForPref(pref_name.c_str());
340 const PrefService::Preference* pref =
341 pref_service->FindPreference(pref_name.c_str());
342 if (!pref) {
343 NOTREACHED();
344 return base::Value::CreateNullValue();
346 const PrefService::Preference* controlling_pref =
347 pref_service->FindPreference(controlling_pref_name.c_str());
348 if (!controlling_pref)
349 controlling_pref = pref;
351 base::DictionaryValue* dict = new base::DictionaryValue;
352 dict->Set("value", pref->GetValue()->DeepCopy());
353 if (controlling_pref->IsManaged()) {
354 dict->SetString("controlledBy", "policy");
355 } else if (controlling_pref->IsExtensionControlled()) {
356 dict->SetString("controlledBy", "extension");
357 Profile* profile = Profile::FromWebUI(web_ui());
358 ExtensionPrefValueMap* extension_pref_value_map =
359 ExtensionPrefValueMapFactory::GetForBrowserContext(profile);
360 std::string extension_id =
361 extension_pref_value_map->GetExtensionControllingPref(
362 controlling_pref->name());
364 ExtensionService* extension_service = extensions::ExtensionSystem::Get(
365 profile)->extension_service();
366 scoped_ptr<base::DictionaryValue> dictionary =
367 extension_service->GetExtensionInfo(extension_id);
368 if (!dictionary->empty())
369 dict->Set("extension", dictionary.release());
370 } else if (controlling_pref->IsRecommended()) {
371 dict->SetString("controlledBy", "recommended");
374 const base::Value* recommended_value =
375 controlling_pref->GetRecommendedValue();
376 if (recommended_value)
377 dict->Set("recommendedValue", recommended_value->DeepCopy());
378 dict->SetBoolean("disabled", !controlling_pref->IsUserModifiable());
379 return dict;
382 PrefService* CoreOptionsHandler::FindServiceForPref(
383 const std::string& pref_name) {
384 // Proxy is a peculiar case: on ChromeOS, settings exist in both user
385 // prefs and local state, but chrome://settings should affect only user prefs.
386 // Elsewhere the proxy settings are stored in local state.
387 // See http://crbug.com/157147
388 PrefService* user_prefs = Profile::FromWebUI(web_ui())->GetPrefs();
389 if (pref_name == prefs::kProxy)
390 #if defined(OS_CHROMEOS)
391 return user_prefs;
392 #else
393 return g_browser_process->local_state();
394 #endif
396 // Find which PrefService contains the given pref. Pref names should not
397 // be duplicated across services, however if they are, prefer the user's
398 // prefs.
399 if (user_prefs->FindPreference(pref_name.c_str()))
400 return user_prefs;
402 if (g_browser_process->local_state()->FindPreference(pref_name.c_str()))
403 return g_browser_process->local_state();
405 return user_prefs;
408 void CoreOptionsHandler::HandleFetchPrefs(const base::ListValue* args) {
409 // First param is name of callback function, so, there needs to be at least
410 // one more element for the actual preference identifier.
411 DCHECK_GE(static_cast<int>(args->GetSize()), 2);
413 // Get callback JS function name.
414 const base::Value* callback;
415 if (!args->Get(0, &callback) || !callback->IsType(base::Value::TYPE_STRING))
416 return;
418 base::string16 callback_function;
419 if (!callback->GetAsString(&callback_function))
420 return;
422 // Get the list of name for prefs to build the response dictionary.
423 base::DictionaryValue result_value;
424 const base::Value* list_member;
426 for (size_t i = 1; i < args->GetSize(); i++) {
427 if (!args->Get(i, &list_member))
428 break;
430 if (!list_member->IsType(base::Value::TYPE_STRING))
431 continue;
433 std::string pref_name;
434 if (!list_member->GetAsString(&pref_name))
435 continue;
437 result_value.Set(pref_name.c_str(), FetchPref(pref_name));
439 web_ui()->CallJavascriptFunction(UTF16ToASCII(callback_function),
440 result_value);
443 void CoreOptionsHandler::HandleObservePrefs(const base::ListValue* args) {
444 // First param is name is JS callback function name, the rest are pref
445 // identifiers that we are observing.
446 DCHECK_GE(static_cast<int>(args->GetSize()), 2);
448 // Get preference change callback function name.
449 std::string callback_func_name;
450 if (!args->GetString(0, &callback_func_name))
451 return;
453 // Get all other parameters - pref identifiers.
454 for (size_t i = 1; i < args->GetSize(); i++) {
455 const base::Value* list_member;
456 if (!args->Get(i, &list_member))
457 break;
459 // Just ignore bad pref identifiers for now.
460 std::string pref_name;
461 if (!list_member->IsType(base::Value::TYPE_STRING) ||
462 !list_member->GetAsString(&pref_name))
463 continue;
465 if (pref_callback_map_.find(pref_name) == pref_callback_map_.end())
466 ObservePref(pref_name);
468 pref_callback_map_.insert(
469 PreferenceCallbackMap::value_type(pref_name, callback_func_name));
473 void CoreOptionsHandler::HandleSetBooleanPref(const base::ListValue* args) {
474 HandleSetPref(args, TYPE_BOOLEAN);
477 void CoreOptionsHandler::HandleSetIntegerPref(const base::ListValue* args) {
478 HandleSetPref(args, TYPE_INTEGER);
481 void CoreOptionsHandler::HandleSetDoublePref(const base::ListValue* args) {
482 HandleSetPref(args, TYPE_DOUBLE);
485 void CoreOptionsHandler::HandleSetStringPref(const base::ListValue* args) {
486 HandleSetPref(args, TYPE_STRING);
489 void CoreOptionsHandler::HandleSetURLPref(const base::ListValue* args) {
490 HandleSetPref(args, TYPE_URL);
493 void CoreOptionsHandler::HandleSetListPref(const base::ListValue* args) {
494 HandleSetPref(args, TYPE_LIST);
497 void CoreOptionsHandler::HandleSetPref(const base::ListValue* args,
498 PrefType type) {
499 DCHECK_GT(static_cast<int>(args->GetSize()), 1);
501 std::string pref_name;
502 if (!args->GetString(0, &pref_name))
503 return;
505 const base::Value* value;
506 if (!args->Get(1, &value))
507 return;
509 scoped_ptr<base::Value> temp_value;
511 switch (type) {
512 case TYPE_BOOLEAN:
513 if (!value->IsType(base::Value::TYPE_BOOLEAN)) {
514 NOTREACHED();
515 return;
517 break;
518 case TYPE_INTEGER: {
519 // In JS all numbers are doubles.
520 double double_value;
521 if (!value->GetAsDouble(&double_value)) {
522 NOTREACHED();
523 return;
525 int int_value = static_cast<int>(double_value);
526 temp_value.reset(new base::FundamentalValue(int_value));
527 value = temp_value.get();
528 break;
530 case TYPE_DOUBLE:
531 if (!value->IsType(base::Value::TYPE_DOUBLE)) {
532 NOTREACHED();
533 return;
535 break;
536 case TYPE_STRING:
537 if (!value->IsType(base::Value::TYPE_STRING)) {
538 NOTREACHED();
539 return;
541 break;
542 case TYPE_URL: {
543 std::string original;
544 if (!value->GetAsString(&original)) {
545 NOTREACHED();
546 return;
548 GURL fixed = URLFixerUpper::FixupURL(original, std::string());
549 temp_value.reset(new base::StringValue(fixed.spec()));
550 value = temp_value.get();
551 break;
553 case TYPE_LIST: {
554 // In case we have a List pref we got a JSON string.
555 std::string json_string;
556 if (!value->GetAsString(&json_string)) {
557 NOTREACHED();
558 return;
560 temp_value.reset(
561 base::JSONReader::Read(json_string));
562 value = temp_value.get();
563 if (!value->IsType(base::Value::TYPE_LIST)) {
564 NOTREACHED();
565 return;
567 break;
569 default:
570 NOTREACHED();
573 std::string metric;
574 if (args->GetSize() > 2 && !args->GetString(2, &metric))
575 LOG(WARNING) << "Invalid metric parameter: " << pref_name;
576 SetPref(pref_name, value, metric);
579 void CoreOptionsHandler::HandleClearPref(const base::ListValue* args) {
580 DCHECK_GT(static_cast<int>(args->GetSize()), 0);
582 std::string pref_name;
583 if (!args->GetString(0, &pref_name))
584 return;
586 std::string metric;
587 if (args->GetSize() > 1) {
588 if (!args->GetString(1, &metric))
589 NOTREACHED();
592 ClearPref(pref_name, metric);
595 void CoreOptionsHandler::HandleUserMetricsAction(const base::ListValue* args) {
596 std::string metric = base::UTF16ToUTF8(ExtractStringValue(args));
597 if (!metric.empty())
598 content::RecordComputedAction(metric);
601 void CoreOptionsHandler::HandleDisableExtension(const base::ListValue* args) {
602 std::string extension_id;
603 if (args->GetString(0, &extension_id)) {
604 ExtensionService* extension_service = extensions::ExtensionSystem::Get(
605 Profile::FromWebUI(web_ui()))->extension_service();
606 DCHECK(extension_service);
607 extension_service->DisableExtension(
608 extension_id, extensions::Extension::DISABLE_USER_ACTION);
609 } else {
610 NOTREACHED();
614 void CoreOptionsHandler::UpdateClearPluginLSOData() {
615 base::FundamentalValue enabled(
616 plugin_status_pref_setter_.IsClearPluginLSODataEnabled());
617 web_ui()->CallJavascriptFunction(
618 "OptionsPage.setClearPluginLSODataEnabled", enabled);
621 void CoreOptionsHandler::UpdatePepperFlashSettingsEnabled() {
622 base::FundamentalValue enabled(
623 plugin_status_pref_setter_.IsPepperFlashSettingsEnabled());
624 web_ui()->CallJavascriptFunction(
625 "OptionsPage.setPepperFlashSettingsEnabled", enabled);
628 } // namespace options