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