options_ui.cc revision 6e8cce623b6e4fe0c9e4af605d675dd9d0338c38
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/options_ui.h"
6
7#include <algorithm>
8#include <vector>
9
10#include "base/basictypes.h"
11#include "base/callback.h"
12#include "base/command_line.h"
13#include "base/memory/ref_counted_memory.h"
14#include "base/memory/singleton.h"
15#include "base/message_loop/message_loop.h"
16#include "base/strings/string_piece.h"
17#include "base/strings/string_util.h"
18#include "base/threading/thread.h"
19#include "base/time/time.h"
20#include "base/values.h"
21#include "chrome/browser/browser_about_handler.h"
22#include "chrome/browser/browser_process.h"
23#include "chrome/browser/profiles/profile.h"
24#include "chrome/browser/ui/webui/metrics_handler.h"
25#include "chrome/browser/ui/webui/options/autofill_options_handler.h"
26#include "chrome/browser/ui/webui/options/automatic_settings_reset_handler.h"
27#include "chrome/browser/ui/webui/options/browser_options_handler.h"
28#include "chrome/browser/ui/webui/options/clear_browser_data_handler.h"
29#include "chrome/browser/ui/webui/options/content_settings_handler.h"
30#include "chrome/browser/ui/webui/options/cookies_view_handler.h"
31#include "chrome/browser/ui/webui/options/core_options_handler.h"
32#include "chrome/browser/ui/webui/options/create_profile_handler.h"
33#include "chrome/browser/ui/webui/options/easy_unlock_handler.h"
34#include "chrome/browser/ui/webui/options/font_settings_handler.h"
35#include "chrome/browser/ui/webui/options/handler_options_handler.h"
36#include "chrome/browser/ui/webui/options/home_page_overlay_handler.h"
37#include "chrome/browser/ui/webui/options/import_data_handler.h"
38#include "chrome/browser/ui/webui/options/language_dictionary_overlay_handler.h"
39#include "chrome/browser/ui/webui/options/language_options_handler.h"
40#include "chrome/browser/ui/webui/options/manage_profile_handler.h"
41#include "chrome/browser/ui/webui/options/media_devices_selection_handler.h"
42#include "chrome/browser/ui/webui/options/password_manager_handler.h"
43#include "chrome/browser/ui/webui/options/reset_profile_settings_handler.h"
44#include "chrome/browser/ui/webui/options/search_engine_manager_handler.h"
45#include "chrome/browser/ui/webui/options/startup_pages_handler.h"
46#include "chrome/browser/ui/webui/options/supervised_user_create_confirm_handler.h"
47#include "chrome/browser/ui/webui/options/supervised_user_import_handler.h"
48#include "chrome/browser/ui/webui/options/supervised_user_learn_more_handler.h"
49#include "chrome/browser/ui/webui/options/website_settings_handler.h"
50#include "chrome/browser/ui/webui/sync_setup_handler.h"
51#include "chrome/browser/ui/webui/theme_source.h"
52#include "chrome/common/url_constants.h"
53#include "components/omnibox/autocomplete_match.h"
54#include "components/omnibox/autocomplete_result.h"
55#include "content/public/browser/notification_types.h"
56#include "content/public/browser/render_frame_host.h"
57#include "content/public/browser/url_data_source.h"
58#include "content/public/browser/web_contents.h"
59#include "content/public/browser/web_contents_delegate.h"
60#include "content/public/browser/web_ui.h"
61#include "grit/chromium_strings.h"
62#include "grit/generated_resources.h"
63#include "grit/locale_settings.h"
64#include "grit/options_resources.h"
65#include "grit/theme_resources.h"
66#include "net/base/escape.h"
67#include "ui/base/l10n/l10n_util.h"
68#include "ui/base/resource/resource_bundle.h"
69#include "ui/base/webui/jstemplate_builder.h"
70#include "ui/base/webui/web_ui_util.h"
71#include "url/gurl.h"
72
73#if defined(OS_CHROMEOS)
74#include "chrome/browser/browser_process_platform_part.h"
75#include "chrome/browser/chromeos/policy/browser_policy_connector_chromeos.h"
76#include "chrome/browser/chromeos/policy/consumer_management_service.h"
77#include "chrome/browser/chromeos/system/pointer_device_observer.h"
78#include "chrome/browser/ui/webui/options/chromeos/accounts_options_handler.h"
79#include "chrome/browser/ui/webui/options/chromeos/bluetooth_options_handler.h"
80#include "chrome/browser/ui/webui/options/chromeos/change_picture_options_handler.h"
81#include "chrome/browser/ui/webui/options/chromeos/consumer_management_handler.h"
82#include "chrome/browser/ui/webui/options/chromeos/core_chromeos_options_handler.h"
83#include "chrome/browser/ui/webui/options/chromeos/cros_language_options_handler.h"
84#include "chrome/browser/ui/webui/options/chromeos/date_time_options_handler.h"
85#include "chrome/browser/ui/webui/options/chromeos/display_options_handler.h"
86#include "chrome/browser/ui/webui/options/chromeos/display_overscan_handler.h"
87#include "chrome/browser/ui/webui/options/chromeos/internet_options_handler.h"
88#include "chrome/browser/ui/webui/options/chromeos/keyboard_handler.h"
89#include "chrome/browser/ui/webui/options/chromeos/pointer_handler.h"
90#include "chrome/browser/ui/webui/options/chromeos/proxy_handler.h"
91#include "chrome/browser/ui/webui/options/chromeos/stats_options_handler.h"
92#include "chrome/browser/ui/webui/options/chromeos/user_image_source.h"
93#include "chrome/browser/ui/webui/options/help_overlay_handler.h"
94#endif
95
96#if defined(USE_NSS)
97#include "chrome/browser/ui/webui/options/certificate_manager_handler.h"
98#endif
99
100#if defined(ENABLE_GOOGLE_NOW)
101#include "chrome/browser/ui/webui/options/geolocation_options_handler.h"
102#endif
103
104using content::RenderViewHost;
105
106namespace {
107
108const char kLocalizedStringsFile[] = "strings.js";
109const char kOptionsBundleJsFile[]  = "options_bundle.js";
110
111}  // namespace
112
113namespace options {
114
115////////////////////////////////////////////////////////////////////////////////
116//
117// OptionsUIHTMLSource
118//
119////////////////////////////////////////////////////////////////////////////////
120
121class OptionsUIHTMLSource : public content::URLDataSource {
122 public:
123  // The constructor takes over ownership of |localized_strings|.
124  explicit OptionsUIHTMLSource(base::DictionaryValue* localized_strings);
125
126  // content::URLDataSource implementation.
127  virtual std::string GetSource() const OVERRIDE;
128  virtual void StartDataRequest(
129      const std::string& path,
130      int render_process_id,
131      int render_frame_id,
132      const content::URLDataSource::GotDataCallback& callback) OVERRIDE;
133  virtual std::string GetMimeType(const std::string&) const OVERRIDE;
134  virtual bool ShouldDenyXFrameOptions() const OVERRIDE;
135
136 private:
137  virtual ~OptionsUIHTMLSource();
138
139  // Localized strings collection.
140  scoped_ptr<base::DictionaryValue> localized_strings_;
141
142  DISALLOW_COPY_AND_ASSIGN(OptionsUIHTMLSource);
143};
144
145OptionsUIHTMLSource::OptionsUIHTMLSource(
146    base::DictionaryValue* localized_strings) {
147  DCHECK(localized_strings);
148  localized_strings_.reset(localized_strings);
149}
150
151std::string OptionsUIHTMLSource::GetSource() const {
152  return chrome::kChromeUISettingsFrameHost;
153}
154
155void OptionsUIHTMLSource::StartDataRequest(
156    const std::string& path,
157    int render_process_id,
158    int render_frame_id,
159    const content::URLDataSource::GotDataCallback& callback) {
160  scoped_refptr<base::RefCountedMemory> response_bytes;
161  webui::SetFontAndTextDirection(localized_strings_.get());
162
163  if (path == kLocalizedStringsFile) {
164    // Return dynamically-generated strings from memory.
165    webui::UseVersion2 version;
166    std::string strings_js;
167    webui::AppendJsonJS(localized_strings_.get(), &strings_js);
168    response_bytes = base::RefCountedString::TakeString(&strings_js);
169  } else if (path == kOptionsBundleJsFile) {
170    // Return (and cache) the options javascript code.
171    response_bytes = ui::ResourceBundle::GetSharedInstance().
172        LoadDataResourceBytes(IDR_OPTIONS_BUNDLE_JS);
173  } else {
174    // Return (and cache) the main options html page as the default.
175    response_bytes = ui::ResourceBundle::GetSharedInstance().
176        LoadDataResourceBytes(IDR_OPTIONS_HTML);
177  }
178
179  callback.Run(response_bytes.get());
180}
181
182std::string OptionsUIHTMLSource::GetMimeType(const std::string& path) const {
183  if (path == kLocalizedStringsFile || path == kOptionsBundleJsFile)
184    return "application/javascript";
185
186  return "text/html";
187}
188
189bool OptionsUIHTMLSource::ShouldDenyXFrameOptions() const {
190  return false;
191}
192
193OptionsUIHTMLSource::~OptionsUIHTMLSource() {}
194
195////////////////////////////////////////////////////////////////////////////////
196//
197// OptionsPageUIHandler
198//
199////////////////////////////////////////////////////////////////////////////////
200
201const char OptionsPageUIHandler::kSettingsAppKey[] = "settingsApp";
202
203OptionsPageUIHandler::OptionsPageUIHandler() {
204}
205
206OptionsPageUIHandler::~OptionsPageUIHandler() {
207}
208
209bool OptionsPageUIHandler::IsEnabled() {
210  return true;
211}
212
213// static
214void OptionsPageUIHandler::RegisterStrings(
215    base::DictionaryValue* localized_strings,
216    const OptionsStringResource* resources,
217    size_t length) {
218  for (size_t i = 0; i < length; ++i) {
219    base::string16 value;
220    if (resources[i].substitution_id == 0) {
221      value = l10n_util::GetStringUTF16(resources[i].id);
222    } else {
223      value = l10n_util::GetStringFUTF16(
224          resources[i].id,
225          l10n_util::GetStringUTF16(resources[i].substitution_id));
226    }
227    localized_strings->SetString(resources[i].name, value);
228  }
229}
230
231void OptionsPageUIHandler::RegisterTitle(
232    base::DictionaryValue* localized_strings,
233    const std::string& variable_name,
234    int title_id) {
235  localized_strings->SetString(variable_name,
236      l10n_util::GetStringUTF16(title_id));
237  localized_strings->SetString(variable_name + "TabTitle",
238      l10n_util::GetStringFUTF16(IDS_OPTIONS_TAB_TITLE,
239          l10n_util::GetStringUTF16(IDS_SETTINGS_TITLE),
240          l10n_util::GetStringUTF16(title_id)));
241}
242
243////////////////////////////////////////////////////////////////////////////////
244//
245// OptionsUI
246//
247////////////////////////////////////////////////////////////////////////////////
248
249OptionsUI::OptionsUI(content::WebUI* web_ui)
250    : WebUIController(web_ui),
251      WebContentsObserver(web_ui->GetWebContents()),
252      initialized_handlers_(false) {
253  base::DictionaryValue* localized_strings = new base::DictionaryValue();
254  localized_strings->Set(OptionsPageUIHandler::kSettingsAppKey,
255                         new base::DictionaryValue());
256
257  CoreOptionsHandler* core_handler;
258#if defined(OS_CHROMEOS)
259  core_handler = new chromeos::options::CoreChromeOSOptionsHandler();
260#else
261  core_handler = new CoreOptionsHandler();
262#endif
263  core_handler->set_handlers_host(this);
264  AddOptionsPageUIHandler(localized_strings, core_handler);
265
266  AddOptionsPageUIHandler(localized_strings, new AutofillOptionsHandler());
267  AddOptionsPageUIHandler(localized_strings,
268                          new AutomaticSettingsResetHandler());
269
270  BrowserOptionsHandler* browser_options_handler = new BrowserOptionsHandler();
271  AddOptionsPageUIHandler(localized_strings, browser_options_handler);
272
273  AddOptionsPageUIHandler(localized_strings, new ClearBrowserDataHandler());
274  AddOptionsPageUIHandler(localized_strings, new ContentSettingsHandler());
275  AddOptionsPageUIHandler(localized_strings, new CookiesViewHandler());
276  AddOptionsPageUIHandler(localized_strings, new CreateProfileHandler());
277  AddOptionsPageUIHandler(localized_strings, new EasyUnlockHandler());
278  AddOptionsPageUIHandler(localized_strings, new FontSettingsHandler());
279#if defined(ENABLE_GOOGLE_NOW)
280  AddOptionsPageUIHandler(localized_strings, new GeolocationOptionsHandler());
281#endif
282  AddOptionsPageUIHandler(localized_strings, new HomePageOverlayHandler());
283  AddOptionsPageUIHandler(localized_strings,
284                          new MediaDevicesSelectionHandler());
285#if defined(OS_CHROMEOS)
286  AddOptionsPageUIHandler(localized_strings,
287                          new chromeos::options::CrosLanguageOptionsHandler());
288#else
289  AddOptionsPageUIHandler(localized_strings, new LanguageOptionsHandler());
290#endif
291  AddOptionsPageUIHandler(localized_strings,
292                          new LanguageDictionaryOverlayHandler());
293  AddOptionsPageUIHandler(localized_strings, new ManageProfileHandler());
294  AddOptionsPageUIHandler(localized_strings, new PasswordManagerHandler());
295  AddOptionsPageUIHandler(localized_strings, new ResetProfileSettingsHandler());
296  AddOptionsPageUIHandler(localized_strings, new SearchEngineManagerHandler());
297  AddOptionsPageUIHandler(localized_strings, new ImportDataHandler());
298  AddOptionsPageUIHandler(localized_strings, new StartupPagesHandler());
299  AddOptionsPageUIHandler(localized_strings,
300                          new SupervisedUserCreateConfirmHandler());
301  AddOptionsPageUIHandler(localized_strings, new SupervisedUserImportHandler());
302  AddOptionsPageUIHandler(localized_strings,
303                          new SupervisedUserLearnMoreHandler());
304  AddOptionsPageUIHandler(localized_strings, new SyncSetupHandler(
305      g_browser_process->profile_manager()));
306  AddOptionsPageUIHandler(localized_strings, new WebsiteSettingsHandler());
307#if defined(OS_CHROMEOS)
308  AddOptionsPageUIHandler(localized_strings,
309                          new chromeos::options::AccountsOptionsHandler());
310  AddOptionsPageUIHandler(localized_strings,
311                          new chromeos::options::BluetoothOptionsHandler());
312  AddOptionsPageUIHandler(localized_strings,
313                          new chromeos::options::DateTimeOptionsHandler());
314  AddOptionsPageUIHandler(localized_strings,
315                          new chromeos::options::DisplayOptionsHandler());
316  AddOptionsPageUIHandler(localized_strings,
317                          new chromeos::options::DisplayOverscanHandler());
318  AddOptionsPageUIHandler(localized_strings,
319                          new chromeos::options::InternetOptionsHandler());
320  AddOptionsPageUIHandler(localized_strings, new options::HelpOverlayHandler());
321  AddOptionsPageUIHandler(localized_strings,
322                          new chromeos::options::KeyboardHandler());
323
324  chromeos::options::PointerHandler* pointer_handler =
325      new chromeos::options::PointerHandler();
326  AddOptionsPageUIHandler(localized_strings, pointer_handler);
327
328  AddOptionsPageUIHandler(localized_strings,
329                          new chromeos::options::ProxyHandler());
330  AddOptionsPageUIHandler(
331      localized_strings,
332      new chromeos::options::ChangePictureOptionsHandler());
333  AddOptionsPageUIHandler(localized_strings,
334                          new chromeos::options::StatsOptionsHandler());
335
336  policy::ConsumerManagementService* consumer_management =
337      g_browser_process->platform_part()->browser_policy_connector_chromeos()->
338          GetConsumerManagementService();
339  chromeos::options::ConsumerManagementHandler* consumer_management_handler =
340      new chromeos::options::ConsumerManagementHandler(consumer_management);
341  AddOptionsPageUIHandler(localized_strings, consumer_management_handler);
342#endif
343#if defined(USE_NSS)
344  AddOptionsPageUIHandler(localized_strings,
345                          new CertificateManagerHandler(false));
346#endif
347  AddOptionsPageUIHandler(localized_strings, new HandlerOptionsHandler());
348
349  web_ui->AddMessageHandler(new MetricsHandler());
350
351  // |localized_strings| ownership is taken over by this constructor.
352  OptionsUIHTMLSource* html_source =
353      new OptionsUIHTMLSource(localized_strings);
354
355  // Set up the chrome://settings-frame/ source.
356  Profile* profile = Profile::FromWebUI(web_ui);
357  content::URLDataSource::Add(profile, html_source);
358
359  // Set up the chrome://theme/ source.
360  ThemeSource* theme = new ThemeSource(profile);
361  content::URLDataSource::Add(profile, theme);
362
363#if defined(OS_CHROMEOS)
364  // Set up the chrome://userimage/ source.
365  chromeos::options::UserImageSource* user_image_source =
366      new chromeos::options::UserImageSource();
367  content::URLDataSource::Add(profile, user_image_source);
368
369  pointer_device_observer_.reset(
370      new chromeos::system::PointerDeviceObserver());
371  pointer_device_observer_->AddObserver(browser_options_handler);
372  pointer_device_observer_->AddObserver(pointer_handler);
373#endif
374}
375
376OptionsUI::~OptionsUI() {
377  // Uninitialize all registered handlers. Deleted by WebUIImpl.
378  for (size_t i = 0; i < handlers_.size(); ++i)
379    handlers_[i]->Uninitialize();
380}
381
382scoped_ptr<OptionsUI::OnFinishedLoadingCallbackList::Subscription>
383OptionsUI::RegisterOnFinishedLoadingCallback(const base::Closure& callback) {
384  return on_finished_loading_callbacks_.Add(callback);
385}
386
387// static
388void OptionsUI::ProcessAutocompleteSuggestions(
389    const AutocompleteResult& result,
390    base::ListValue* const suggestions) {
391  for (size_t i = 0; i < result.size(); ++i) {
392    const AutocompleteMatch& match = result.match_at(i);
393    AutocompleteMatchType::Type type = match.type;
394    if (type != AutocompleteMatchType::HISTORY_URL &&
395        type != AutocompleteMatchType::HISTORY_TITLE &&
396        type != AutocompleteMatchType::HISTORY_BODY &&
397        type != AutocompleteMatchType::HISTORY_KEYWORD &&
398        type != AutocompleteMatchType::NAVSUGGEST &&
399        type != AutocompleteMatchType::NAVSUGGEST_PERSONALIZED) {
400      continue;
401    }
402    base::DictionaryValue* entry = new base::DictionaryValue();
403    entry->SetString("title", match.description);
404    entry->SetString("displayURL", match.contents);
405    entry->SetString("url", match.destination_url.spec());
406    suggestions->Append(entry);
407  }
408}
409
410// static
411base::RefCountedMemory* OptionsUI::GetFaviconResourceBytes(
412      ui::ScaleFactor scale_factor) {
413  return ui::ResourceBundle::GetSharedInstance().
414      LoadDataResourceBytesForScale(IDR_SETTINGS_FAVICON, scale_factor);
415}
416
417void OptionsUI::DidStartProvisionalLoadForFrame(
418    content::RenderFrameHost* render_frame_host,
419    const GURL& validated_url,
420    bool is_error_page,
421    bool is_iframe_srcdoc) {
422  if (render_frame_host->GetRenderViewHost() ==
423          web_ui()->GetWebContents()->GetRenderViewHost() &&
424      validated_url.host() == chrome::kChromeUISettingsFrameHost) {
425    for (size_t i = 0; i < handlers_.size(); ++i)
426      handlers_[i]->PageLoadStarted();
427  }
428}
429
430void OptionsUI::InitializeHandlers() {
431  Profile* profile = Profile::FromWebUI(web_ui());
432  DCHECK(!profile->IsOffTheRecord() || profile->IsGuestSession());
433
434  // A new web page DOM has been brought up in an existing renderer, causing
435  // this method to be called twice. If that happens, ignore the second call.
436  if (!initialized_handlers_) {
437    for (size_t i = 0; i < handlers_.size(); ++i)
438      handlers_[i]->InitializeHandler();
439    initialized_handlers_ = true;
440
441#if defined(OS_CHROMEOS)
442    pointer_device_observer_->Init();
443#endif
444  }
445
446#if defined(OS_CHROMEOS)
447  pointer_device_observer_->CheckDevices();
448#endif
449
450  // Always initialize the page as when handlers are left over we still need to
451  // do various things like show/hide sections and send data to the Javascript.
452  for (size_t i = 0; i < handlers_.size(); ++i)
453    handlers_[i]->InitializePage();
454
455  web_ui()->CallJavascriptFunction(
456      "BrowserOptions.notifyInitializationComplete");
457}
458
459void OptionsUI::OnFinishedLoading() {
460  on_finished_loading_callbacks_.Notify();
461}
462
463void OptionsUI::AddOptionsPageUIHandler(
464    base::DictionaryValue* localized_strings,
465    OptionsPageUIHandler* handler_raw) {
466  scoped_ptr<OptionsPageUIHandler> handler(handler_raw);
467  DCHECK(handler.get());
468  // Add only if handler's service is enabled.
469  if (handler->IsEnabled()) {
470    // Add handler to the list and also pass the ownership.
471    web_ui()->AddMessageHandler(handler.release());
472    handler_raw->GetLocalizedValues(localized_strings);
473    handlers_.push_back(handler_raw);
474  }
475}
476
477}  // namespace options
478