Home | History | Annotate | Download | only in options
      1 // Copyright (c) 2011 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/about_page_handler.h"
      6 
      7 #include <vector>
      8 
      9 #include "base/basictypes.h"
     10 #include "base/callback.h"
     11 #include "base/command_line.h"
     12 #include "base/i18n/time_formatting.h"
     13 #include "base/string16.h"
     14 #include "base/string_number_conversions.h"
     15 #include "base/time.h"
     16 #include "base/utf_string_conversions.h"
     17 #include "base/values.h"
     18 #include "chrome/browser/google/google_util.h"
     19 #include "chrome/browser/platform_util.h"
     20 #include "chrome/common/chrome_version_info.h"
     21 #include "chrome/common/url_constants.h"
     22 #include "googleurl/src/gurl.h"
     23 #include "grit/chromium_strings.h"
     24 #include "grit/generated_resources.h"
     25 #include "grit/locale_settings.h"
     26 #include "grit/theme_resources.h"
     27 #include "ui/base/l10n/l10n_util.h"
     28 #include "ui/base/resource/resource_bundle.h"
     29 #include "webkit/glue/webkit_glue.h"
     30 
     31 #if defined(CHROME_V8)
     32 #include "v8/include/v8.h"
     33 #endif
     34 
     35 #if defined(OS_CHROMEOS)
     36 #include "chrome/browser/chromeos/cros/cros_library.h"
     37 #include "chrome/browser/chromeos/cros/power_library.h"
     38 #include "chrome/browser/chromeos/cros/update_library.h"
     39 #include "chrome/browser/chromeos/login/user_manager.h"
     40 #include "chrome/browser/chromeos/login/wizard_controller.h"
     41 #endif
     42 
     43 namespace {
     44 
     45 // These are used as placeholder text around the links in the text in the
     46 // license.
     47 const char kBeginLink[] = "BEGIN_LINK";
     48 const char kEndLink[] = "END_LINK";
     49 const char kBeginLinkChr[] = "BEGIN_LINK_CHR";
     50 const char kBeginLinkOss[] = "BEGIN_LINK_OSS";
     51 const char kEndLinkChr[] = "END_LINK_CHR";
     52 const char kEndLinkOss[] = "END_LINK_OSS";
     53 #if defined(OS_CHROMEOS)
     54 const char kBeginLinkCrosOss[] = "BEGIN_LINK_CROS_OSS";
     55 const char kEndLinkCrosOss[] = "END_LINK_CROS_OSS";
     56 #endif
     57 
     58 // Returns a substring [start, end) from |text|.
     59 std::string StringSubRange(const std::string& text, size_t start,
     60                            size_t end) {
     61   DCHECK(end > start);
     62   return text.substr(start, end - start);
     63 }
     64 
     65 }  // namespace
     66 
     67 #if defined(OS_CHROMEOS)
     68 
     69 class AboutPageHandler::UpdateObserver
     70     : public chromeos::UpdateLibrary::Observer {
     71  public:
     72   explicit UpdateObserver(AboutPageHandler* handler) : page_handler_(handler) {}
     73   virtual ~UpdateObserver() {}
     74 
     75   AboutPageHandler* page_handler() const { return page_handler_; }
     76 
     77  private:
     78   virtual void UpdateStatusChanged(chromeos::UpdateLibrary* object) {
     79     page_handler_->UpdateStatus(object->status());
     80   }
     81 
     82   AboutPageHandler* page_handler_;
     83 
     84   DISALLOW_COPY_AND_ASSIGN(UpdateObserver);
     85 };
     86 
     87 #endif
     88 
     89 AboutPageHandler::AboutPageHandler()
     90 #if defined(OS_CHROMEOS)
     91     : progress_(-1),
     92       sticky_(false),
     93       started_(false)
     94 #endif
     95 {}
     96 
     97 AboutPageHandler::~AboutPageHandler() {
     98 #if defined(OS_CHROMEOS)
     99   if (update_observer_.get()) {
    100     chromeos::CrosLibrary::Get()->GetUpdateLibrary()->
    101         RemoveObserver(update_observer_.get());
    102   }
    103 #endif
    104 }
    105 
    106 void AboutPageHandler::GetLocalizedValues(DictionaryValue* localized_strings) {
    107   DCHECK(localized_strings);
    108 
    109   static OptionsStringResource resources[] = {
    110 #if defined (OS_CHROMEOS)
    111     { "firmware", IDS_ABOUT_PAGE_FIRMWARE },
    112     { "product", IDS_PRODUCT_OS_NAME },
    113     { "os", IDS_PRODUCT_OS_NAME },
    114     { "loading", IDS_ABOUT_PAGE_LOADING },
    115     { "check_now", IDS_ABOUT_PAGE_CHECK_NOW },
    116     { "update_status", IDS_UPGRADE_CHECK_STARTED },
    117     { "restart_now", IDS_RELAUNCH_AND_UPDATE },
    118 #else
    119     { "product", IDS_PRODUCT_NAME },
    120     { "check_now", IDS_ABOUT_CHROME_UPDATE_CHECK },
    121 #endif
    122     { "browser", IDS_PRODUCT_NAME },
    123     { "more_info", IDS_ABOUT_PAGE_MORE_INFO },
    124     { "copyright", IDS_ABOUT_VERSION_COPYRIGHT },
    125     { "channel", IDS_ABOUT_PAGE_CHANNEL },
    126     { "stable", IDS_ABOUT_PAGE_CHANNEL_STABLE },
    127     { "beta", IDS_ABOUT_PAGE_CHANNEL_BETA },
    128     { "dev", IDS_ABOUT_PAGE_CHANNEL_DEVELOPMENT },
    129     { "canary", IDS_ABOUT_PAGE_CHANNEL_CANARY },
    130     { "channel_warning_header", IDS_ABOUT_PAGE_CHANNEL_WARNING_HEADER },
    131     { "channel_warning_text", IDS_ABOUT_PAGE_CHANNEL_WARNING_TEXT },
    132     { "user_agent", IDS_ABOUT_VERSION_USER_AGENT },
    133     { "command_line", IDS_ABOUT_VERSION_COMMAND_LINE },
    134   };
    135 
    136   RegisterStrings(localized_strings, resources, arraysize(resources));
    137   RegisterTitle(localized_strings, "aboutPage", IDS_ABOUT_TAB_TITLE);
    138 
    139   // browser version
    140 
    141   chrome::VersionInfo version_info;
    142   DCHECK(version_info.is_valid());
    143 
    144   std::string browser_version = version_info.Version();
    145   std::string version_modifier = platform_util::GetVersionStringModifier();
    146   if (!version_modifier.empty())
    147     browser_version += " " + version_modifier;
    148 
    149 #if !defined(GOOGLE_CHROME_BUILD)
    150   browser_version += " (";
    151   browser_version += version_info.LastChange();
    152   browser_version += ")";
    153 #endif
    154 
    155   localized_strings->SetString("browser_version", browser_version);
    156 
    157   // license
    158 
    159   std::string text = l10n_util::GetStringUTF8(IDS_ABOUT_VERSION_LICENSE);
    160 
    161   bool chromium_url_appears_first =
    162       text.find(kBeginLinkChr) < text.find(kBeginLinkOss);
    163 
    164   size_t link1 = text.find(kBeginLink);
    165   DCHECK(link1 != std::string::npos);
    166   size_t link1_end = text.find(kEndLink, link1);
    167   DCHECK(link1_end != std::string::npos);
    168   size_t link2 = text.find(kBeginLink, link1_end);
    169   DCHECK(link2 != std::string::npos);
    170   size_t link2_end = text.find(kEndLink, link2);
    171   DCHECK(link2_end != std::string::npos);
    172 
    173   localized_strings->SetString("license_content_0", text.substr(0, link1));
    174   localized_strings->SetString("license_content_1",
    175       StringSubRange(text, link1_end + strlen(kEndLinkOss), link2));
    176   localized_strings->SetString("license_content_2",
    177       text.substr(link2_end + strlen(kEndLinkOss)));
    178 
    179   // The Chromium link within the main text of the dialog.
    180   localized_strings->SetString(chromium_url_appears_first ?
    181       "license_link_content_0" : "license_link_content_1",
    182       StringSubRange(text,
    183                      text.find(kBeginLinkChr) + strlen(kBeginLinkChr),
    184                      text.find(kEndLinkChr)));
    185   GURL url = google_util::AppendGoogleLocaleParam(
    186       GURL(chrome::kChromiumProjectURL));
    187   localized_strings->SetString(chromium_url_appears_first ?
    188       "license_link_0" : "license_link_1", url.spec());
    189 
    190   // The Open Source link within the main text of the dialog.  We need to use
    191   // the chrome:// variant instead of about:credits; the latter will get
    192   // rewritten to about:blank.
    193   localized_strings->SetString(chromium_url_appears_first ?
    194       "license_link_content_1" : "license_link_content_0",
    195       StringSubRange(text,
    196                      text.find(kBeginLinkOss) + strlen(kBeginLinkOss),
    197                      text.find(kEndLinkOss)));
    198   localized_strings->SetString(chromium_url_appears_first ?
    199       "license_link_1" : "license_link_0", chrome::kChromeUIAboutCreditsURL);
    200 
    201 #if defined(OS_CHROMEOS)
    202   std::string cros_text =
    203       l10n_util::GetStringUTF8(IDS_ABOUT_CROS_VERSION_LICENSE);
    204 
    205   size_t cros_link = cros_text.find(kBeginLinkCrosOss);
    206   DCHECK(cros_link != std::string::npos);
    207   size_t cros_link_end = cros_text.find(kEndLinkCrosOss, cros_link);
    208   DCHECK(cros_link_end != std::string::npos);
    209 
    210   localized_strings->SetString("cros_license_content_0",
    211       cros_text.substr(0, cros_link));
    212   localized_strings->SetString("cros_license_content_1",
    213       cros_text.substr(cros_link_end + strlen(kEndLinkCrosOss)));
    214   localized_strings->SetString("cros_license_link_content_0",
    215       StringSubRange(cros_text, cros_link + strlen(kBeginLinkCrosOss),
    216                      cros_link_end));
    217   localized_strings->SetString("cros_license_link_0",
    218       chrome::kChromeUIAboutOSCreditsURL);
    219 #endif
    220 
    221   // webkit
    222 
    223   localized_strings->SetString("webkit_version",
    224                                webkit_glue::GetWebKitVersion());
    225 
    226   // javascript
    227 
    228 #if defined(CHROME_V8)
    229   localized_strings->SetString("js_engine", "V8");
    230   localized_strings->SetString("js_engine_version", v8::V8::GetVersion());
    231 #else
    232   localized_strings->SetString("js_engine", "JavaScriptCore");
    233   localized_strings->SetString("js_engine_version",
    234                                webkit_glue::GetWebKitVersion());
    235 #endif
    236 
    237   // user agent
    238 
    239   localized_strings->SetString("user_agent_info",
    240                                webkit_glue::GetUserAgent(GURL()));
    241 
    242   // command line
    243 
    244 #if defined(OS_WIN)
    245   localized_strings->SetString("command_line_info",
    246       WideToUTF16(CommandLine::ForCurrentProcess()->command_line_string()));
    247 #elif defined(OS_POSIX)
    248   // TODO(viettrungluu): something horrible might happen if there are non-UTF-8
    249   // arguments (since |SetString()| requires Unicode).
    250   std::string command_line = "";
    251   typedef std::vector<std::string> ArgvList;
    252   const ArgvList& argv = CommandLine::ForCurrentProcess()->argv();
    253   for (ArgvList::const_iterator iter = argv.begin(); iter != argv.end(); iter++)
    254     command_line += " " + *iter;
    255   localized_strings->SetString("command_line_info", command_line);
    256 #endif
    257 }
    258 
    259 void AboutPageHandler::RegisterMessages() {
    260   web_ui_->RegisterMessageCallback("PageReady",
    261       NewCallback(this, &AboutPageHandler::PageReady));
    262   web_ui_->RegisterMessageCallback("SetReleaseTrack",
    263       NewCallback(this, &AboutPageHandler::SetReleaseTrack));
    264 
    265 #if defined(OS_CHROMEOS)
    266   web_ui_->RegisterMessageCallback("CheckNow",
    267       NewCallback(this, &AboutPageHandler::CheckNow));
    268   web_ui_->RegisterMessageCallback("RestartNow",
    269       NewCallback(this, &AboutPageHandler::RestartNow));
    270 #endif
    271 }
    272 
    273 void AboutPageHandler::PageReady(const ListValue* args) {
    274 #if defined(OS_CHROMEOS)
    275   // Version information is loaded from a callback
    276   loader_.EnablePlatformVersions(true);
    277   loader_.GetVersion(&consumer_,
    278                      NewCallback(this, &AboutPageHandler::OnOSVersion),
    279                      chromeos::VersionLoader::VERSION_FULL);
    280   loader_.GetFirmware(&consumer_,
    281                       NewCallback(this, &AboutPageHandler::OnOSFirmware));
    282 
    283   chromeos::UpdateLibrary* update_library =
    284       chromeos::CrosLibrary::Get()->GetUpdateLibrary();
    285 
    286   update_observer_.reset(new UpdateObserver(this));
    287   update_library->AddObserver(update_observer_.get());
    288 
    289   // Update the WebUI page with the current status. See comments below.
    290   UpdateStatus(update_library->status());
    291 
    292   // Initiate update check. UpdateStatus() below will be called when we
    293   // get update status via update_observer_. If the update has been
    294   // already complete, update_observer_ won't receive a notification.
    295   // This is why we manually update the WebUI page above.
    296   CheckNow(NULL);
    297 
    298   // Request the channel information. Use the observer to track the about
    299   // page handler and ensure it does not get deleted before the callback.
    300   update_library->GetReleaseTrack(UpdateSelectedChannel,
    301                                   update_observer_.get());
    302 #endif
    303 }
    304 
    305 void AboutPageHandler::SetReleaseTrack(const ListValue* args) {
    306 #if defined(OS_CHROMEOS)
    307   if (!chromeos::UserManager::Get()->current_user_is_owner()) {
    308     LOG(WARNING) << "Non-owner tried to change release track.";
    309     return;
    310   }
    311   const std::string channel = UTF16ToUTF8(ExtractStringValue(args));
    312   chromeos::CrosLibrary::Get()->GetUpdateLibrary()->SetReleaseTrack(channel);
    313 #endif
    314 }
    315 
    316 #if defined(OS_CHROMEOS)
    317 
    318 void AboutPageHandler::CheckNow(const ListValue* args) {
    319   // Make sure that libcros is loaded and OOBE is complete.
    320   if (chromeos::CrosLibrary::Get()->EnsureLoaded() &&
    321       (!WizardController::default_controller() ||
    322         WizardController::IsDeviceRegistered())) {
    323     chromeos::CrosLibrary::Get()->GetUpdateLibrary()->
    324         RequestUpdateCheck(NULL,   // no callback
    325                            NULL);  // no userdata
    326   }
    327 }
    328 
    329 void AboutPageHandler::RestartNow(const ListValue* args) {
    330   chromeos::CrosLibrary::Get()->GetPowerLibrary()->RequestRestart();
    331 }
    332 
    333 void AboutPageHandler::UpdateStatus(
    334     const chromeos::UpdateLibrary::Status& status) {
    335   string16 message;
    336   std::string image = "up-to-date";
    337   bool enabled = false;
    338 
    339   switch (status.status) {
    340     case chromeos::UPDATE_STATUS_IDLE:
    341       if (!sticky_) {
    342         message = l10n_util::GetStringFUTF16(IDS_UPGRADE_ALREADY_UP_TO_DATE,
    343             l10n_util::GetStringUTF16(IDS_PRODUCT_OS_NAME));
    344         enabled = true;
    345       }
    346       break;
    347     case chromeos::UPDATE_STATUS_CHECKING_FOR_UPDATE:
    348       message = l10n_util::GetStringUTF16(IDS_UPGRADE_CHECK_STARTED);
    349       sticky_ = false;
    350       break;
    351     case chromeos::UPDATE_STATUS_UPDATE_AVAILABLE:
    352       message = l10n_util::GetStringUTF16(IDS_UPDATE_AVAILABLE);
    353       started_ = true;
    354       break;
    355     case chromeos::UPDATE_STATUS_DOWNLOADING:
    356     {
    357       int progress = static_cast<int>(status.download_progress * 100.0);
    358       if (progress != progress_) {
    359         progress_ = progress;
    360         message = l10n_util::GetStringFUTF16Int(IDS_UPDATE_DOWNLOADING,
    361                                                 progress_);
    362       }
    363       started_ = true;
    364     }
    365       break;
    366     case chromeos::UPDATE_STATUS_VERIFYING:
    367       message = l10n_util::GetStringUTF16(IDS_UPDATE_VERIFYING);
    368       started_ = true;
    369       break;
    370     case chromeos::UPDATE_STATUS_FINALIZING:
    371       message = l10n_util::GetStringUTF16(IDS_UPDATE_FINALIZING);
    372       started_ = true;
    373       break;
    374     case chromeos::UPDATE_STATUS_UPDATED_NEED_REBOOT:
    375       message = l10n_util::GetStringUTF16(IDS_UPDATE_COMPLETED);
    376       image = "available";
    377       sticky_ = true;
    378       break;
    379     default:
    380     // case UPDATE_STATUS_ERROR:
    381     // case UPDATE_STATUS_REPORTING_ERROR_EVENT:
    382 
    383     // The error is only displayed if we were able to determine an
    384     // update was available.
    385       if (started_) {
    386         message = l10n_util::GetStringUTF16(IDS_UPDATE_ERROR);
    387         image = "fail";
    388         enabled = true;
    389         sticky_ = true;
    390         started_ = false;
    391       }
    392       break;
    393   }
    394   if (message.size()) {
    395     scoped_ptr<Value> update_message(Value::CreateStringValue(message));
    396     // "Checking for update..." needs to be shown for a while, so users
    397     // can read it, hence insert delay for this.
    398     scoped_ptr<Value> insert_delay(Value::CreateBooleanValue(
    399         status.status == chromeos::UPDATE_STATUS_CHECKING_FOR_UPDATE));
    400     web_ui_->CallJavascriptFunction("AboutPage.updateStatusCallback",
    401                                     *update_message, *insert_delay);
    402 
    403     scoped_ptr<Value> enabled_value(Value::CreateBooleanValue(enabled));
    404     web_ui_->CallJavascriptFunction("AboutPage.updateEnableCallback",
    405                                     *enabled_value);
    406 
    407     scoped_ptr<Value> image_string(Value::CreateStringValue(image));
    408     web_ui_->CallJavascriptFunction("AboutPage.setUpdateImage",
    409                                     *image_string);
    410   }
    411   // We'll change the "Check For Update" button to "Restart" button.
    412   if (status.status == chromeos::UPDATE_STATUS_UPDATED_NEED_REBOOT) {
    413     web_ui_->CallJavascriptFunction("AboutPage.changeToRestartButton");
    414   }
    415 }
    416 
    417 void AboutPageHandler::OnOSVersion(chromeos::VersionLoader::Handle handle,
    418                                    std::string version) {
    419   if (version.size()) {
    420     scoped_ptr<Value> version_string(Value::CreateStringValue(version));
    421     web_ui_->CallJavascriptFunction("AboutPage.updateOSVersionCallback",
    422                                     *version_string);
    423   }
    424 }
    425 
    426 void AboutPageHandler::OnOSFirmware(chromeos::VersionLoader::Handle handle,
    427                                     std::string firmware) {
    428   if (firmware.size()) {
    429     scoped_ptr<Value> firmware_string(Value::CreateStringValue(firmware));
    430     web_ui_->CallJavascriptFunction("AboutPage.updateOSFirmwareCallback",
    431                                     *firmware_string);
    432   }
    433 }
    434 
    435 // Callback from UpdateEngine with channel information.
    436 // static
    437 void AboutPageHandler::UpdateSelectedChannel(void* user_data,
    438                                              const char* channel) {
    439   if (!user_data || !channel) {
    440     LOG(WARNING) << "UpdateSelectedChannel returned NULL.";
    441     return;
    442   }
    443   UpdateObserver* observer = static_cast<UpdateObserver*>(user_data);
    444   if (chromeos::CrosLibrary::Get()->GetUpdateLibrary()->HasObserver(observer)) {
    445     // If UpdateLibrary still has the observer, then the page handler is valid.
    446     AboutPageHandler* handler = observer->page_handler();
    447     scoped_ptr<Value> channel_string(Value::CreateStringValue(channel));
    448     handler->web_ui_->CallJavascriptFunction(
    449         "AboutPage.updateSelectedOptionCallback", *channel_string);
    450   }
    451 }
    452 
    453 #endif  // defined(OS_CHROMEOS)
    454