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