Home | History | Annotate | Download | only in offline
      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/chromeos/offline/offline_load_page.h"
      6 
      7 #include "ash/shell.h"
      8 #include "ash/shell_delegate.h"
      9 #include "ash/system/tray/system_tray_delegate.h"
     10 #include "base/i18n/rtl.h"
     11 #include "base/metrics/histogram.h"
     12 #include "base/strings/string_piece.h"
     13 #include "base/strings/stringprintf.h"
     14 #include "base/strings/utf_string_conversions.h"
     15 #include "base/values.h"
     16 #include "chrome/browser/chrome_notification_types.h"
     17 #include "chrome/browser/extensions/extension_service.h"
     18 #include "chrome/browser/extensions/extension_system.h"
     19 #include "chrome/browser/profiles/profile.h"
     20 #include "chrome/browser/renderer_preferences_util.h"
     21 #include "chrome/browser/tab_contents/tab_util.h"
     22 #include "chrome/common/extensions/extension.h"
     23 #include "chrome/common/extensions/extension_constants.h"
     24 #include "chrome/common/extensions/extension_icon_set.h"
     25 #include "chrome/common/extensions/manifest_handlers/icons_handler.h"
     26 #include "chrome/common/url_constants.h"
     27 #include "content/public/browser/browser_thread.h"
     28 #include "content/public/browser/interstitial_page.h"
     29 #include "content/public/browser/notification_types.h"
     30 #include "content/public/browser/web_contents.h"
     31 #include "grit/browser_resources.h"
     32 #include "grit/chromium_strings.h"
     33 #include "grit/generated_resources.h"
     34 #include "grit/google_chrome_strings.h"
     35 #include "grit/theme_resources.h"
     36 #include "net/base/escape.h"
     37 #include "ui/base/l10n/l10n_util.h"
     38 #include "ui/base/resource/resource_bundle.h"
     39 #include "ui/webui/jstemplate_builder.h"
     40 #include "ui/webui/web_ui_util.h"
     41 
     42 using content::BrowserThread;
     43 using content::InterstitialPage;
     44 using content::WebContents;
     45 
     46 namespace {
     47 
     48 // Maximum time to show a blank page.
     49 const int kMaxBlankPeriod = 3000;
     50 
     51 // A utility function to set the dictionary's value given by |resource_id|.
     52 void SetString(DictionaryValue* strings, const char* name, int resource_id) {
     53   strings->SetString(name, l10n_util::GetStringUTF16(resource_id));
     54 }
     55 
     56 }  // namespace
     57 
     58 namespace chromeos {
     59 
     60 OfflineLoadPage::OfflineLoadPage(WebContents* web_contents,
     61                                  const GURL& url,
     62                                  const CompletionCallback& callback)
     63     : callback_(callback),
     64       proceeded_(false),
     65       web_contents_(web_contents),
     66       url_(url) {
     67   net::NetworkChangeNotifier::AddConnectionTypeObserver(this);
     68   interstitial_page_ = InterstitialPage::Create(web_contents, true, url, this);
     69 }
     70 
     71 OfflineLoadPage::~OfflineLoadPage() {
     72   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
     73   net::NetworkChangeNotifier::RemoveConnectionTypeObserver(this);
     74 }
     75 
     76 void OfflineLoadPage::Show() {
     77   interstitial_page_->Show();
     78 }
     79 
     80 std::string OfflineLoadPage::GetHTMLContents() {
     81   DictionaryValue strings;
     82   int64 time_to_wait = kMaxBlankPeriod;
     83   // Set the timeout to show the page.
     84   strings.SetInteger("time_to_wait", static_cast<int>(time_to_wait));
     85 
     86   // Button labels
     87   SetString(&strings, "msg", IDS_OFFLINE_LOAD_DESCRIPTION);
     88   SetString(&strings, "network_settings", IDS_OFFLINE_NETWORK_SETTINGS);
     89   SetString(&strings, "product_name", IDS_SHORT_PRODUCT_NAME_LOWER);
     90 
     91   // Get the Chromium/Chrome icon, we can't access the icon via chrome://theme
     92   // on the webpage since the interstitial page isn't a webui and doesn't have
     93   // access to chrome:// URL's.
     94   strings.SetString("icon",
     95                     webui::GetBitmapDataUrlFromResource(IDR_PRODUCT_LOGO_32));
     96 
     97   webui::SetFontAndTextDirection(&strings);
     98   string16 failed_url(ASCIIToUTF16(url_.spec()));
     99   if (base::i18n::IsRTL())
    100     base::i18n::WrapStringWithLTRFormatting(&failed_url);
    101   strings.SetString("url", failed_url);
    102 
    103   // The offline page for app has icons and slightly different message.
    104   Profile* profile = Profile::FromBrowserContext(
    105       web_contents_->GetBrowserContext());
    106   DCHECK(profile);
    107   const extensions::Extension* extension = NULL;
    108   ExtensionService* extensions_service =
    109       extensions::ExtensionSystem::Get(profile)->extension_service();
    110   // Extension service does not exist in test.
    111   if (extensions_service)
    112     extension = extensions_service->extensions()->GetHostedAppByURL(url_);
    113 
    114   if (extension)
    115     GetAppOfflineStrings(extension, &strings);
    116   else
    117     GetNormalOfflineStrings(&strings);
    118 
    119   base::StringPiece html(
    120       ResourceBundle::GetSharedInstance().GetRawDataResource(
    121           IDR_OFFLINE_LOAD_HTML));
    122   return webui::GetI18nTemplateHtml(html, &strings);
    123 }
    124 
    125  void OfflineLoadPage::OverrideRendererPrefs(
    126       content::RendererPreferences* prefs) {
    127   Profile* profile = Profile::FromBrowserContext(
    128       web_contents_->GetBrowserContext());
    129   renderer_preferences_util::UpdateFromSystemSettings(prefs, profile);
    130 }
    131 
    132 void OfflineLoadPage::OnProceed() {
    133   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
    134   proceeded_ = true;
    135   NotifyBlockingPageComplete(true);
    136 }
    137 
    138 void OfflineLoadPage::OnDontProceed() {
    139   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
    140   // Ignore if it's already proceeded.
    141   if (proceeded_)
    142     return;
    143   NotifyBlockingPageComplete(false);
    144 }
    145 
    146 void OfflineLoadPage::GetAppOfflineStrings(
    147     const extensions::Extension* app,
    148     DictionaryValue* strings) const {
    149   strings->SetString("title", app->name());
    150   strings->SetString(
    151       "heading", l10n_util::GetStringUTF16(IDS_APP_OFFLINE_LOAD_HEADLINE));
    152 }
    153 
    154 void OfflineLoadPage::GetNormalOfflineStrings(DictionaryValue* strings) const {
    155   strings->SetString("title", web_contents_->GetTitle());
    156   strings->SetString(
    157       "heading", l10n_util::GetStringUTF16(IDS_SITE_OFFLINE_LOAD_HEADLINE));
    158 }
    159 
    160 void OfflineLoadPage::CommandReceived(const std::string& cmd) {
    161   std::string command(cmd);
    162   // The Jasonified response has quotes, remove them.
    163   if (command.length() > 1 && command[0] == '"') {
    164     command = command.substr(1, command.length() - 2);
    165   }
    166   // TODO(oshima): record action for metrics.
    167   if (command == "open_network_settings") {
    168     ash::Shell::GetInstance()->system_tray_delegate()->ShowNetworkSettings("");
    169   } else {
    170     LOG(WARNING) << "Unknown command:" << cmd;
    171   }
    172 }
    173 
    174 void OfflineLoadPage::NotifyBlockingPageComplete(bool proceed) {
    175   BrowserThread::PostTask(
    176       BrowserThread::IO, FROM_HERE, base::Bind(callback_, proceed));
    177 }
    178 
    179 void OfflineLoadPage::OnConnectionTypeChanged(
    180     net::NetworkChangeNotifier::ConnectionType type) {
    181   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
    182   const bool online = type != net::NetworkChangeNotifier::CONNECTION_NONE;
    183   DVLOG(1) << "ConnectionTypeObserver notification received: state="
    184            << (online ? "online" : "offline");
    185   if (online) {
    186     net::NetworkChangeNotifier::RemoveConnectionTypeObserver(this);
    187     interstitial_page_->Proceed();
    188   }
    189 }
    190 
    191 }  // namespace chromeos
    192