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