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