core_options_handler.cc revision f8ee788a64d60abd8f2d742a5fdedde054ecd910
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.
4
5#include "chrome/browser/ui/webui/options/core_options_handler.h"
6
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_service.h"
18#include "chrome/browser/extensions/extension_util.h"
19#include "chrome/browser/profiles/profile.h"
20#include "chrome/browser/ui/options/options_util.h"
21#include "chrome/common/pref_names.h"
22#include "chrome/common/url_constants.h"
23#include "components/url_fixer/url_fixer.h"
24#include "content/public/browser/notification_details.h"
25#include "content/public/browser/notification_types.h"
26#include "content/public/browser/user_metrics.h"
27#include "content/public/browser/web_ui.h"
28#include "extensions/browser/extension_pref_value_map.h"
29#include "extensions/browser/extension_pref_value_map_factory.h"
30#include "extensions/browser/extension_registry.h"
31#include "extensions/browser/extension_system.h"
32#include "extensions/common/extension.h"
33#include "grit/chromium_strings.h"
34#include "grit/generated_resources.h"
35#include "grit/locale_settings.h"
36#include "grit/theme_resources.h"
37#include "ui/base/l10n/l10n_util.h"
38#include "url/gurl.h"
39
40using base::UserMetricsAction;
41
42namespace options {
43
44namespace {
45
46// Only allow changes to the metrics reporting checkbox if we were succesfully
47// able to change the service.
48bool AllowMetricsReportingChange(const base::Value* to_value) {
49  bool enable;
50  if (!to_value->GetAsBoolean(&enable)) {
51    NOTREACHED();
52    return false;
53  }
54
55  return enable == OptionsUtil::ResolveMetricsReportingEnabled(enable);
56}
57
58// Whether "controlledBy" property of pref value sent to options web UI needs to
59// be set to "extension" when the preference is controlled by an extension.
60bool CanSetExtensionControlledPrefValue(
61    const PrefService::Preference* preference) {
62#if defined(OS_WIN)
63  // These have more obvious UI than the standard one for extension controlled
64  // values (an extension puzzle piece) on the settings page. To avoiding
65  // showing the extension puzzle piece for these settings, their "controlledBy"
66  // value should never be set to "extension".
67  return preference->name() != prefs::kURLsToRestoreOnStartup &&
68         preference->name() != prefs::kRestoreOnStartup &&
69         preference->name() != prefs::kHomePage &&
70         preference->name() != prefs::kHomePageIsNewTabPage;
71#else
72  return true;
73#endif
74}
75
76}  // namespace
77
78CoreOptionsHandler::CoreOptionsHandler()
79    : handlers_host_(NULL) {
80}
81
82CoreOptionsHandler::~CoreOptionsHandler() {}
83
84void CoreOptionsHandler::InitializeHandler() {
85  Profile* profile = Profile::FromWebUI(web_ui());
86
87  plugin_status_pref_setter_.Init(
88      profile,
89      base::Bind(&CoreOptionsHandler::OnPreferenceChanged,
90                 base::Unretained(this),
91                 profile->GetPrefs()));
92
93  pref_change_filters_[prefs::kMetricsReportingEnabled] =
94      base::Bind(&AllowMetricsReportingChange);
95}
96
97void CoreOptionsHandler::InitializePage() {
98  UpdateClearPluginLSOData();
99  UpdatePepperFlashSettingsEnabled();
100}
101
102void CoreOptionsHandler::GetLocalizedValues(
103    base::DictionaryValue* localized_strings) {
104  GetStaticLocalizedValues(localized_strings);
105}
106
107void CoreOptionsHandler::GetStaticLocalizedValues(
108    base::DictionaryValue* localized_strings) {
109  DCHECK(localized_strings);
110  // Main
111  localized_strings->SetString("optionsPageTitle",
112      l10n_util::GetStringUTF16(IDS_SETTINGS_TITLE));
113
114  // Controlled settings bubble.
115  localized_strings->SetString("controlledSettingPolicy",
116      l10n_util::GetStringUTF16(IDS_OPTIONS_CONTROLLED_SETTING_POLICY));
117  localized_strings->SetString("controlledSettingExtension",
118      l10n_util::GetStringUTF16(IDS_OPTIONS_CONTROLLED_SETTING_EXTENSION));
119  localized_strings->SetString("controlledSettingExtensionWithName",
120      l10n_util::GetStringUTF16(
121          IDS_OPTIONS_CONTROLLED_SETTING_EXTENSION_WITH_NAME));
122  localized_strings->SetString("controlledSettingManageExtension",
123      l10n_util::GetStringUTF16(
124          IDS_OPTIONS_CONTROLLED_SETTING_MANAGE_EXTENSION));
125  localized_strings->SetString("controlledSettingDisableExtension",
126      l10n_util::GetStringUTF16(IDS_EXTENSIONS_DISABLE));
127  localized_strings->SetString("controlledSettingRecommended",
128      l10n_util::GetStringUTF16(IDS_OPTIONS_CONTROLLED_SETTING_RECOMMENDED));
129  localized_strings->SetString("controlledSettingHasRecommendation",
130      l10n_util::GetStringUTF16(
131          IDS_OPTIONS_CONTROLLED_SETTING_HAS_RECOMMENDATION));
132  localized_strings->SetString("controlledSettingFollowRecommendation",
133      l10n_util::GetStringUTF16(
134          IDS_OPTIONS_CONTROLLED_SETTING_FOLLOW_RECOMMENDATION));
135  localized_strings->SetString("controlledSettingsPolicy",
136      l10n_util::GetStringUTF16(IDS_OPTIONS_CONTROLLED_SETTINGS_POLICY));
137  localized_strings->SetString("controlledSettingsExtension",
138      l10n_util::GetStringUTF16(IDS_OPTIONS_CONTROLLED_SETTINGS_EXTENSION));
139  localized_strings->SetString("controlledSettingsExtensionWithName",
140      l10n_util::GetStringUTF16(
141          IDS_OPTIONS_CONTROLLED_SETTINGS_EXTENSION_WITH_NAME));
142
143  // Search
144  RegisterTitle(localized_strings, "searchPage", IDS_OPTIONS_SEARCH_PAGE_TITLE);
145  localized_strings->SetString("searchPlaceholder",
146      l10n_util::GetStringUTF16(IDS_OPTIONS_SEARCH_PLACEHOLDER));
147  localized_strings->SetString("searchPageNoMatches",
148      l10n_util::GetStringUTF16(IDS_OPTIONS_SEARCH_PAGE_NO_MATCHES));
149  localized_strings->SetString("searchPageHelpLabel",
150      l10n_util::GetStringUTF16(IDS_OPTIONS_SEARCH_PAGE_HELP_LABEL));
151  localized_strings->SetString("searchPageHelpTitle",
152      l10n_util::GetStringFUTF16(IDS_OPTIONS_SEARCH_PAGE_HELP_TITLE,
153          l10n_util::GetStringUTF16(IDS_PRODUCT_NAME)));
154  localized_strings->SetString("searchPageHelpURL",
155                               chrome::kSettingsSearchHelpURL);
156
157  // Common
158  localized_strings->SetString("ok",
159      l10n_util::GetStringUTF16(IDS_OK));
160  localized_strings->SetString("cancel",
161      l10n_util::GetStringUTF16(IDS_CANCEL));
162  localized_strings->SetString("learnMore",
163      l10n_util::GetStringUTF16(IDS_LEARN_MORE));
164  localized_strings->SetString("close",
165      l10n_util::GetStringUTF16(IDS_CLOSE));
166  localized_strings->SetString("done",
167      l10n_util::GetStringUTF16(IDS_DONE));
168  localized_strings->SetString("deletableItemDeleteButtonTitle",
169      l10n_util::GetStringUTF16(IDS_OPTIONS_DELETABLE_ITEM_DELETE_BUTTON));
170}
171
172void CoreOptionsHandler::Uninitialize() {
173  std::string last_pref;
174  for (PreferenceCallbackMap::const_iterator iter = pref_callback_map_.begin();
175       iter != pref_callback_map_.end();
176       ++iter) {
177    if (last_pref != iter->first) {
178      StopObservingPref(iter->first);
179      last_pref = iter->first;
180    }
181  }
182}
183
184void CoreOptionsHandler::OnPreferenceChanged(PrefService* service,
185                                             const std::string& pref_name) {
186  if (pref_name == prefs::kClearPluginLSODataEnabled) {
187    // This preference is stored in Local State, not in the user preferences.
188    UpdateClearPluginLSOData();
189    return;
190  }
191  if (pref_name == prefs::kPepperFlashSettingsEnabled) {
192    UpdatePepperFlashSettingsEnabled();
193    return;
194  }
195  NotifyPrefChanged(pref_name, std::string());
196}
197
198void CoreOptionsHandler::RegisterMessages() {
199  registrar_.Init(Profile::FromWebUI(web_ui())->GetPrefs());
200  local_state_registrar_.Init(g_browser_process->local_state());
201
202  web_ui()->RegisterMessageCallback("coreOptionsInitialize",
203      base::Bind(&CoreOptionsHandler::HandleInitialize,
204                 base::Unretained(this)));
205  web_ui()->RegisterMessageCallback("onFinishedLoadingOptions",
206      base::Bind(&CoreOptionsHandler::OnFinishedLoading,
207                 base::Unretained(this)));
208  web_ui()->RegisterMessageCallback("fetchPrefs",
209      base::Bind(&CoreOptionsHandler::HandleFetchPrefs,
210                 base::Unretained(this)));
211  web_ui()->RegisterMessageCallback("observePrefs",
212      base::Bind(&CoreOptionsHandler::HandleObservePrefs,
213                 base::Unretained(this)));
214  web_ui()->RegisterMessageCallback("setBooleanPref",
215      base::Bind(&CoreOptionsHandler::HandleSetBooleanPref,
216                 base::Unretained(this)));
217  web_ui()->RegisterMessageCallback("setIntegerPref",
218      base::Bind(&CoreOptionsHandler::HandleSetIntegerPref,
219                 base::Unretained(this)));
220  web_ui()->RegisterMessageCallback("setDoublePref",
221      base::Bind(&CoreOptionsHandler::HandleSetDoublePref,
222                 base::Unretained(this)));
223  web_ui()->RegisterMessageCallback("setStringPref",
224      base::Bind(&CoreOptionsHandler::HandleSetStringPref,
225                 base::Unretained(this)));
226  web_ui()->RegisterMessageCallback("setURLPref",
227      base::Bind(&CoreOptionsHandler::HandleSetURLPref,
228                 base::Unretained(this)));
229  web_ui()->RegisterMessageCallback("setListPref",
230      base::Bind(&CoreOptionsHandler::HandleSetListPref,
231                 base::Unretained(this)));
232  web_ui()->RegisterMessageCallback("clearPref",
233      base::Bind(&CoreOptionsHandler::HandleClearPref,
234                 base::Unretained(this)));
235  web_ui()->RegisterMessageCallback("coreOptionsUserMetricsAction",
236      base::Bind(&CoreOptionsHandler::HandleUserMetricsAction,
237                 base::Unretained(this)));
238  web_ui()->RegisterMessageCallback("disableExtension",
239      base::Bind(&CoreOptionsHandler::HandleDisableExtension,
240                 base::Unretained(this)));
241}
242
243void CoreOptionsHandler::HandleInitialize(const base::ListValue* args) {
244  DCHECK(handlers_host_);
245  handlers_host_->InitializeHandlers();
246}
247
248void CoreOptionsHandler::OnFinishedLoading(const base::ListValue* args) {
249  DCHECK(handlers_host_);
250  handlers_host_->OnFinishedLoading();
251}
252
253base::Value* CoreOptionsHandler::FetchPref(const std::string& pref_name) {
254  return CreateValueForPref(pref_name, std::string());
255}
256
257void CoreOptionsHandler::ObservePref(const std::string& pref_name) {
258  if (g_browser_process->local_state()->FindPreference(pref_name.c_str())) {
259    local_state_registrar_.Add(
260        pref_name.c_str(),
261        base::Bind(&CoreOptionsHandler::OnPreferenceChanged,
262                   base::Unretained(this),
263                   local_state_registrar_.prefs()));
264  }
265  // TODO(pneubeck): change this to if/else once kProxy is only used as a user
266  // pref. Currently, it is both a user and a local state pref.
267  if (Profile::FromWebUI(web_ui())->GetPrefs()->FindPreference(
268          pref_name.c_str())) {
269    registrar_.Add(
270        pref_name.c_str(),
271        base::Bind(&CoreOptionsHandler::OnPreferenceChanged,
272                   base::Unretained(this),
273                   registrar_.prefs()));
274  }
275}
276
277void CoreOptionsHandler::StopObservingPref(const std::string& pref_name) {
278  if (g_browser_process->local_state()->FindPreference(pref_name.c_str()))
279    local_state_registrar_.Remove(pref_name.c_str());
280  else
281    registrar_.Remove(pref_name.c_str());
282}
283
284void CoreOptionsHandler::SetPref(const std::string& pref_name,
285                                 const base::Value* value,
286                                 const std::string& metric) {
287  PrefService* pref_service = FindServiceForPref(pref_name);
288  PrefChangeFilterMap::iterator iter = pref_change_filters_.find(pref_name);
289  if (iter != pref_change_filters_.end()) {
290    // Also check if the pref is user modifiable (don't even try to run the
291    // filter function if the user is not allowed to change the pref).
292    const PrefService::Preference* pref =
293        pref_service->FindPreference(pref_name.c_str());
294    if ((pref && !pref->IsUserModifiable()) || !iter->second.Run(value)) {
295      // Reject the change; remind the page of the true value.
296      NotifyPrefChanged(pref_name, std::string());
297      return;
298    }
299  }
300
301  switch (value->GetType()) {
302    case base::Value::TYPE_BOOLEAN:
303    case base::Value::TYPE_INTEGER:
304    case base::Value::TYPE_DOUBLE:
305    case base::Value::TYPE_STRING:
306    case base::Value::TYPE_LIST:
307      pref_service->Set(pref_name.c_str(), *value);
308      break;
309
310    default:
311      NOTREACHED();
312      return;
313  }
314
315  ProcessUserMetric(value, metric);
316}
317
318void CoreOptionsHandler::ClearPref(const std::string& pref_name,
319                                   const std::string& metric) {
320  PrefService* pref_service = FindServiceForPref(pref_name);
321  pref_service->ClearPref(pref_name.c_str());
322
323  if (!metric.empty())
324    content::RecordComputedAction(metric);
325}
326
327void CoreOptionsHandler::ProcessUserMetric(const base::Value* value,
328                                           const std::string& metric) {
329  if (metric.empty())
330    return;
331
332  std::string metric_string = metric;
333  if (value->IsType(base::Value::TYPE_BOOLEAN)) {
334    bool bool_value;
335    CHECK(value->GetAsBoolean(&bool_value));
336    metric_string += bool_value ? "_Enable" : "_Disable";
337  }
338
339  content::RecordComputedAction(metric_string);
340}
341
342void CoreOptionsHandler::NotifyPrefChanged(
343    const std::string& pref_name,
344    const std::string& controlling_pref_name) {
345  scoped_ptr<base::Value> value(
346      CreateValueForPref(pref_name, controlling_pref_name));
347  DispatchPrefChangeNotification(pref_name, value.Pass());
348}
349
350void CoreOptionsHandler::DispatchPrefChangeNotification(
351    const std::string& name,
352    scoped_ptr<base::Value> value) {
353  std::pair<PreferenceCallbackMap::const_iterator,
354            PreferenceCallbackMap::const_iterator> range =
355      pref_callback_map_.equal_range(name);
356  base::ListValue result_value;
357  result_value.Append(new base::StringValue(name.c_str()));
358  result_value.Append(value.release());
359  for (PreferenceCallbackMap::const_iterator iter = range.first;
360       iter != range.second; ++iter) {
361    const std::string& callback_function = iter->second;
362    web_ui()->CallJavascriptFunction(callback_function, result_value);
363  }
364}
365
366base::Value* CoreOptionsHandler::CreateValueForPref(
367    const std::string& pref_name,
368    const std::string& controlling_pref_name) {
369  const PrefService* pref_service = FindServiceForPref(pref_name.c_str());
370  const PrefService::Preference* pref =
371      pref_service->FindPreference(pref_name.c_str());
372  if (!pref) {
373    NOTREACHED();
374    return base::Value::CreateNullValue();
375  }
376  const PrefService::Preference* controlling_pref =
377      pref_service->FindPreference(controlling_pref_name.c_str());
378  if (!controlling_pref)
379    controlling_pref = pref;
380
381  base::DictionaryValue* dict = new base::DictionaryValue;
382  dict->Set("value", pref->GetValue()->DeepCopy());
383  if (controlling_pref->IsManaged()) {
384    dict->SetString("controlledBy", "policy");
385  } else if (controlling_pref->IsExtensionControlled() &&
386             CanSetExtensionControlledPrefValue(controlling_pref)) {
387    Profile* profile = Profile::FromWebUI(web_ui());
388    ExtensionPrefValueMap* extension_pref_value_map =
389        ExtensionPrefValueMapFactory::GetForBrowserContext(profile);
390    std::string extension_id =
391        extension_pref_value_map->GetExtensionControllingPref(
392            controlling_pref->name());
393
394    const extensions::Extension* extension =
395        extensions::ExtensionRegistry::Get(profile)->GetExtensionById(
396            extension_id, extensions::ExtensionRegistry::EVERYTHING);
397    if (extension) {
398      dict->SetString("controlledBy", "extension");
399      dict->Set("extension",
400                extensions::util::GetExtensionInfo(extension).release());
401    }
402  } else if (controlling_pref->IsRecommended()) {
403    dict->SetString("controlledBy", "recommended");
404  }
405
406  const base::Value* recommended_value =
407      controlling_pref->GetRecommendedValue();
408  if (recommended_value)
409    dict->Set("recommendedValue", recommended_value->DeepCopy());
410  dict->SetBoolean("disabled", !controlling_pref->IsUserModifiable());
411  return dict;
412}
413
414PrefService* CoreOptionsHandler::FindServiceForPref(
415    const std::string& pref_name) {
416  // Proxy is a peculiar case: on ChromeOS, settings exist in both user
417  // prefs and local state, but chrome://settings should affect only user prefs.
418  // Elsewhere the proxy settings are stored in local state.
419  // See http://crbug.com/157147
420  PrefService* user_prefs = Profile::FromWebUI(web_ui())->GetPrefs();
421  if (pref_name == prefs::kProxy)
422#if defined(OS_CHROMEOS)
423    return user_prefs;
424#else
425    return g_browser_process->local_state();
426#endif
427
428  // Find which PrefService contains the given pref. Pref names should not
429  // be duplicated across services, however if they are, prefer the user's
430  // prefs.
431  if (user_prefs->FindPreference(pref_name.c_str()))
432    return user_prefs;
433
434  if (g_browser_process->local_state()->FindPreference(pref_name.c_str()))
435    return g_browser_process->local_state();
436
437  return user_prefs;
438}
439
440void CoreOptionsHandler::HandleFetchPrefs(const base::ListValue* args) {
441  // First param is name of callback function, so, there needs to be at least
442  // one more element for the actual preference identifier.
443  DCHECK_GE(static_cast<int>(args->GetSize()), 2);
444
445  // Get callback JS function name.
446  const base::Value* callback;
447  if (!args->Get(0, &callback) || !callback->IsType(base::Value::TYPE_STRING))
448    return;
449
450  base::string16 callback_function;
451  if (!callback->GetAsString(&callback_function))
452    return;
453
454  // Get the list of name for prefs to build the response dictionary.
455  base::DictionaryValue result_value;
456  const base::Value* list_member;
457
458  for (size_t i = 1; i < args->GetSize(); i++) {
459    if (!args->Get(i, &list_member))
460      break;
461
462    if (!list_member->IsType(base::Value::TYPE_STRING))
463      continue;
464
465    std::string pref_name;
466    if (!list_member->GetAsString(&pref_name))
467      continue;
468
469    result_value.Set(pref_name.c_str(), FetchPref(pref_name));
470  }
471  web_ui()->CallJavascriptFunction(base::UTF16ToASCII(callback_function),
472                                   result_value);
473}
474
475void CoreOptionsHandler::HandleObservePrefs(const base::ListValue* args) {
476  // First param is name is JS callback function name, the rest are pref
477  // identifiers that we are observing.
478  DCHECK_GE(static_cast<int>(args->GetSize()), 2);
479
480  // Get preference change callback function name.
481  std::string callback_func_name;
482  if (!args->GetString(0, &callback_func_name))
483    return;
484
485  // Get all other parameters - pref identifiers.
486  for (size_t i = 1; i < args->GetSize(); i++) {
487    const base::Value* list_member;
488    if (!args->Get(i, &list_member))
489      break;
490
491    // Just ignore bad pref identifiers for now.
492    std::string pref_name;
493    if (!list_member->IsType(base::Value::TYPE_STRING) ||
494        !list_member->GetAsString(&pref_name))
495      continue;
496
497    if (pref_callback_map_.find(pref_name) == pref_callback_map_.end())
498      ObservePref(pref_name);
499
500    pref_callback_map_.insert(
501        PreferenceCallbackMap::value_type(pref_name, callback_func_name));
502  }
503}
504
505void CoreOptionsHandler::HandleSetBooleanPref(const base::ListValue* args) {
506  HandleSetPref(args, TYPE_BOOLEAN);
507}
508
509void CoreOptionsHandler::HandleSetIntegerPref(const base::ListValue* args) {
510  HandleSetPref(args, TYPE_INTEGER);
511}
512
513void CoreOptionsHandler::HandleSetDoublePref(const base::ListValue* args) {
514  HandleSetPref(args, TYPE_DOUBLE);
515}
516
517void CoreOptionsHandler::HandleSetStringPref(const base::ListValue* args) {
518  HandleSetPref(args, TYPE_STRING);
519}
520
521void CoreOptionsHandler::HandleSetURLPref(const base::ListValue* args) {
522  HandleSetPref(args, TYPE_URL);
523}
524
525void CoreOptionsHandler::HandleSetListPref(const base::ListValue* args) {
526  HandleSetPref(args, TYPE_LIST);
527}
528
529void CoreOptionsHandler::HandleSetPref(const base::ListValue* args,
530                                       PrefType type) {
531  DCHECK_GT(static_cast<int>(args->GetSize()), 1);
532
533  std::string pref_name;
534  if (!args->GetString(0, &pref_name))
535    return;
536
537  const base::Value* value;
538  if (!args->Get(1, &value))
539    return;
540
541  scoped_ptr<base::Value> temp_value;
542
543  switch (type) {
544    case TYPE_BOOLEAN:
545      if (!value->IsType(base::Value::TYPE_BOOLEAN)) {
546        NOTREACHED();
547        return;
548      }
549      break;
550    case TYPE_INTEGER: {
551      // In JS all numbers are doubles.
552      double double_value;
553      if (!value->GetAsDouble(&double_value)) {
554        NOTREACHED();
555        return;
556      }
557      int int_value = static_cast<int>(double_value);
558      temp_value.reset(new base::FundamentalValue(int_value));
559      value = temp_value.get();
560      break;
561    }
562    case TYPE_DOUBLE:
563      if (!value->IsType(base::Value::TYPE_DOUBLE)) {
564        NOTREACHED();
565        return;
566      }
567      break;
568    case TYPE_STRING:
569      if (!value->IsType(base::Value::TYPE_STRING)) {
570        NOTREACHED();
571        return;
572      }
573      break;
574    case TYPE_URL: {
575      std::string original;
576      if (!value->GetAsString(&original)) {
577        NOTREACHED();
578        return;
579      }
580      GURL fixed = url_fixer::FixupURL(original, std::string());
581      temp_value.reset(new base::StringValue(fixed.spec()));
582      value = temp_value.get();
583      break;
584    }
585    case TYPE_LIST: {
586      // In case we have a List pref we got a JSON string.
587      std::string json_string;
588      if (!value->GetAsString(&json_string)) {
589        NOTREACHED();
590        return;
591      }
592      temp_value.reset(
593          base::JSONReader::Read(json_string));
594      value = temp_value.get();
595      if (!value->IsType(base::Value::TYPE_LIST)) {
596        NOTREACHED();
597        return;
598      }
599      break;
600    }
601    default:
602      NOTREACHED();
603  }
604
605  std::string metric;
606  if (args->GetSize() > 2 && !args->GetString(2, &metric))
607    LOG(WARNING) << "Invalid metric parameter: " << pref_name;
608  SetPref(pref_name, value, metric);
609}
610
611void CoreOptionsHandler::HandleClearPref(const base::ListValue* args) {
612  DCHECK_GT(static_cast<int>(args->GetSize()), 0);
613
614  std::string pref_name;
615  if (!args->GetString(0, &pref_name))
616    return;
617
618  std::string metric;
619  if (args->GetSize() > 1) {
620    if (!args->GetString(1, &metric))
621      NOTREACHED();
622  }
623
624  ClearPref(pref_name, metric);
625}
626
627void CoreOptionsHandler::HandleUserMetricsAction(const base::ListValue* args) {
628  std::string metric = base::UTF16ToUTF8(ExtractStringValue(args));
629  if (!metric.empty())
630    content::RecordComputedAction(metric);
631}
632
633void CoreOptionsHandler::HandleDisableExtension(const base::ListValue* args) {
634  std::string extension_id;
635  if (args->GetString(0, &extension_id)) {
636    ExtensionService* extension_service = extensions::ExtensionSystem::Get(
637        Profile::FromWebUI(web_ui()))->extension_service();
638    DCHECK(extension_service);
639    extension_service->DisableExtension(
640        extension_id, extensions::Extension::DISABLE_USER_ACTION);
641  } else {
642    NOTREACHED();
643  }
644}
645
646void CoreOptionsHandler::UpdateClearPluginLSOData() {
647  base::FundamentalValue enabled(
648          plugin_status_pref_setter_.IsClearPluginLSODataEnabled());
649  web_ui()->CallJavascriptFunction(
650      "OptionsPage.setClearPluginLSODataEnabled", enabled);
651}
652
653void CoreOptionsHandler::UpdatePepperFlashSettingsEnabled() {
654  base::FundamentalValue enabled(
655          plugin_status_pref_setter_.IsPepperFlashSettingsEnabled());
656  web_ui()->CallJavascriptFunction(
657      "OptionsPage.setPepperFlashSettingsEnabled", enabled);
658}
659
660}  // namespace options
661