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