Home | History | Annotate | Download | only in options
      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