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