blob: 08704991a29b5121077c6aeb4970c230d7b32054 [file] [log] [blame]
[email protected]cce15bb2014-06-17 13:43:511// Copyright 2014 The Chromium Authors. All rights reserved.
[email protected]a09159a2012-11-29 12:51:482// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
[email protected]cce15bb2014-06-17 13:43:515#include "chrome/browser/supervised_user/supervised_user_interstitial.h"
[email protected]a09159a2012-11-29 12:51:486
treibe7ccb7e2014-09-09 19:21:457#include "base/memory/weak_ptr.h"
[email protected]2c145422013-01-24 18:15:408#include "base/metrics/histogram.h"
[email protected]3853a4c2013-02-11 17:15:579#include "base/prefs/pref_service.h"
[email protected]95c47d02014-08-19 09:17:5010#include "base/strings/string_number_conversions.h"
[email protected]112158af2013-06-07 23:46:1811#include "base/strings/utf_string_conversions.h"
[email protected]59f21562013-05-23 16:19:3012#include "base/values.h"
[email protected]93c23212013-09-19 14:22:3813#include "chrome/browser/infobars/infobar_service.h"
[email protected]a09159a2012-11-29 12:51:4814#include "chrome/browser/profiles/profile.h"
[email protected]cce15bb2014-06-17 13:43:5115#include "chrome/browser/supervised_user/supervised_user_service.h"
16#include "chrome/browser/supervised_user/supervised_user_service_factory.h"
[email protected]a09159a2012-11-29 12:51:4817#include "chrome/common/pref_names.h"
[email protected]af39f002014-08-22 10:18:1818#include "chrome/grit/generated_resources.h"
[email protected]051655ad2014-04-18 15:09:4119#include "components/infobars/core/infobar.h"
20#include "components/infobars/core/infobar_delegate.h"
[email protected]a09159a2012-11-29 12:51:4821#include "content/public/browser/browser_thread.h"
22#include "content/public/browser/interstitial_page.h"
[email protected]93c23212013-09-19 14:22:3823#include "content/public/browser/navigation_controller.h"
24#include "content/public/browser/navigation_details.h"
25#include "content/public/browser/navigation_entry.h"
[email protected]a09159a2012-11-29 12:51:4826#include "content/public/browser/web_contents.h"
treibe7ccb7e2014-09-09 19:21:4527#include "content/public/browser/web_contents_user_data.h"
[email protected]59f21562013-05-23 16:19:3028#include "content/public/browser/web_ui.h"
[email protected]a09159a2012-11-29 12:51:4829#include "grit/browser_resources.h"
[email protected]a09159a2012-11-29 12:51:4830#include "ui/base/l10n/l10n_util.h"
31#include "ui/base/resource/resource_bundle.h"
[email protected]cd67ed52013-10-15 01:22:1332#include "ui/base/webui/jstemplate_builder.h"
33#include "ui/base/webui/web_ui_util.h"
[email protected]a09159a2012-11-29 12:51:4834
treibe7ccb7e2014-09-09 19:21:4535#if !defined(OS_ANDROID)
36#include "chrome/browser/ui/browser_finder.h"
37#include "chrome/browser/ui/tabs/tab_strip_model.h"
38#endif
39
[email protected]a09159a2012-11-29 12:51:4840using content::BrowserThread;
treibe7ccb7e2014-09-09 19:21:4541using content::WebContents;
[email protected]a09159a2012-11-29 12:51:4842
[email protected]95c47d02014-08-19 09:17:5043namespace {
44
45static const int kAvatarSize1x = 45;
46static const int kAvatarSize2x = 90;
47
treib885fee12014-08-29 08:07:5848std::string BuildAvatarImageUrl(const std::string& url, int size) {
[email protected]95c47d02014-08-19 09:17:5049 std::string result = url;
50 size_t slash = result.rfind('/');
51 if (slash != std::string::npos)
52 result.insert(slash, "/s" + base::IntToString(size));
treib885fee12014-08-29 08:07:5853 return result;
[email protected]95c47d02014-08-19 09:17:5054}
55
treibe7ccb7e2014-09-09 19:21:4556class TabCloser : public content::WebContentsUserData<TabCloser> {
57 // To use, call TabCloser::CreateForWebContents.
58 private:
59 friend class content::WebContentsUserData<TabCloser>;
60
61 explicit TabCloser(WebContents* web_contents)
62 : web_contents_(web_contents), weak_ptr_factory_(this) {
63 BrowserThread::PostTask(
64 BrowserThread::UI,
65 FROM_HERE,
66 base::Bind(&TabCloser::CloseTabImpl, weak_ptr_factory_.GetWeakPtr()));
67 }
68 virtual ~TabCloser() {}
69
70 void CloseTabImpl() {
71 // On Android, FindBrowserWithWebContents and TabStripModel don't exist.
72#if !defined(OS_ANDROID)
73 Browser* browser = chrome::FindBrowserWithWebContents(web_contents_);
74 DCHECK(browser);
75 TabStripModel* tab_strip = browser->tab_strip_model();
76 DCHECK_NE(TabStripModel::kNoTab,
77 tab_strip->GetIndexOfWebContents(web_contents_));
78 if (tab_strip->count() <= 1) {
79 // Don't close the last tab in the window.
80 web_contents_->RemoveUserData(UserDataKey());
81 return;
82 }
83#endif
84 web_contents_->Close();
85 }
86
87 WebContents* web_contents_;
88 base::WeakPtrFactory<TabCloser> weak_ptr_factory_;
89};
90
91} // namespace
92
93DEFINE_WEB_CONTENTS_USER_DATA_KEY(TabCloser);
[email protected]95c47d02014-08-19 09:17:5094
[email protected]b8af2d12014-04-29 07:30:4295// static
[email protected]95c47d02014-08-19 09:17:5096void SupervisedUserInterstitial::Show(
treibe7ccb7e2014-09-09 19:21:4597 WebContents* web_contents,
[email protected]95c47d02014-08-19 09:17:5098 const GURL& url,
99 const base::Callback<void(bool)>& callback) {
[email protected]cce15bb2014-06-17 13:43:51100 SupervisedUserInterstitial* interstitial =
101 new SupervisedUserInterstitial(web_contents, url, callback);
[email protected]b8af2d12014-04-29 07:30:42102
103 // If Init() does not complete fully, immediately delete the interstitial.
104 if (!interstitial->Init())
105 delete interstitial;
106 // Otherwise |interstitial_page_| is responsible for deleting it.
107}
108
[email protected]cce15bb2014-06-17 13:43:51109SupervisedUserInterstitial::SupervisedUserInterstitial(
treibe7ccb7e2014-09-09 19:21:45110 WebContents* web_contents,
[email protected]a09159a2012-11-29 12:51:48111 const GURL& url,
112 const base::Callback<void(bool)>& callback)
113 : web_contents_(web_contents),
treibab0a39e2014-09-24 14:48:28114 profile_(Profile::FromBrowserContext(web_contents->GetBrowserContext())),
[email protected]61f5da22013-09-05 15:52:10115 interstitial_page_(NULL),
[email protected]a09159a2012-11-29 12:51:48116 url_(url),
[email protected]b8af2d12014-04-29 07:30:42117 callback_(callback) {}
118
treibab0a39e2014-09-24 14:48:28119SupervisedUserInterstitial::~SupervisedUserInterstitial() {
120 DCHECK(!web_contents_);
121}
[email protected]b8af2d12014-04-29 07:30:42122
[email protected]cce15bb2014-06-17 13:43:51123bool SupervisedUserInterstitial::Init() {
[email protected]61f5da22013-09-05 15:52:10124 if (ShouldProceed()) {
125 // It can happen that the site was only allowed very recently and the URL
126 // filter on the IO thread had not been updated yet. Proceed with the
127 // request without showing the interstitial.
128 DispatchContinueRequest(true);
[email protected]b8af2d12014-04-29 07:30:42129 return false;
[email protected]61f5da22013-09-05 15:52:10130 }
131
[email protected]b8af2d12014-04-29 07:30:42132 InfoBarService* service = InfoBarService::FromWebContents(web_contents_);
[email protected]93c23212013-09-19 14:22:38133 if (service) {
[email protected]b8af2d12014-04-29 07:30:42134 // Remove all the infobars which are attached to |web_contents_| and for
[email protected]93c23212013-09-19 14:22:38135 // which ShouldExpire() returns true.
136 content::LoadCommittedDetails details;
137 // |details.is_in_page| is default false, and |details.is_main_frame| is
138 // default true. This results in is_navigation_to_different_page() returning
139 // true.
140 DCHECK(details.is_navigation_to_different_page());
141 const content::NavigationController& controller =
[email protected]b8af2d12014-04-29 07:30:42142 web_contents_->GetController();
[email protected]93c23212013-09-19 14:22:38143 details.entry = controller.GetActiveEntry();
144 if (controller.GetLastCommittedEntry()) {
145 details.previous_entry_index = controller.GetLastCommittedEntryIndex();
146 details.previous_url = controller.GetLastCommittedEntry()->GetURL();
147 }
148 details.type = content::NAVIGATION_TYPE_NEW_PAGE;
[email protected]b44f1d32014-04-10 13:53:26149 for (int i = service->infobar_count() - 1; i >= 0; --i) {
[email protected]051655ad2014-04-18 15:09:41150 infobars::InfoBar* infobar = service->infobar_at(i);
[email protected]5daf1d92014-04-04 15:52:13151 if (infobar->delegate()->ShouldExpire(
152 InfoBarService::NavigationDetailsFromLoadCommittedDetails(
153 details)))
[email protected]b44f1d32014-04-10 13:53:26154 service->RemoveInfoBar(infobar);
[email protected]93c23212013-09-19 14:22:38155 }
156 }
157
treibab0a39e2014-09-24 14:48:28158 SupervisedUserService* supervised_user_service =
159 SupervisedUserServiceFactory::GetForProfile(profile_);
160 supervised_user_service->AddObserver(this);
[email protected]a09159a2012-11-29 12:51:48161
[email protected]0369d6ab2013-08-09 01:52:59162 interstitial_page_ =
[email protected]b8af2d12014-04-29 07:30:42163 content::InterstitialPage::Create(web_contents_, true, url_, this);
[email protected]a09159a2012-11-29 12:51:48164 interstitial_page_->Show();
[email protected]a09159a2012-11-29 12:51:48165
[email protected]b8af2d12014-04-29 07:30:42166 return true;
167}
[email protected]a09159a2012-11-29 12:51:48168
[email protected]cce15bb2014-06-17 13:43:51169std::string SupervisedUserInterstitial::GetHTMLContents() {
[email protected]cb1078de2013-12-23 20:04:22170 base::DictionaryValue strings;
[email protected]a09159a2012-11-29 12:51:48171 strings.SetString("blockPageTitle",
172 l10n_util::GetStringUTF16(IDS_BLOCK_INTERSTITIAL_TITLE));
[email protected]fae057a2013-06-21 22:46:08173
[email protected]cce15bb2014-06-17 13:43:51174 SupervisedUserService* supervised_user_service =
treibab0a39e2014-09-24 14:48:28175 SupervisedUserServiceFactory::GetForProfile(profile_);
[email protected]0369d6ab2013-08-09 01:52:59176
[email protected]cce15bb2014-06-17 13:43:51177 bool allow_access_requests = supervised_user_service->AccessRequestsEnabled();
[email protected]0369d6ab2013-08-09 01:52:59178 strings.SetBoolean("allowAccessRequests", allow_access_requests);
179
treibab0a39e2014-09-24 14:48:28180 std::string profile_image_url = profile_->GetPrefs()->GetString(
[email protected]95c47d02014-08-19 09:17:50181 prefs::kSupervisedUserCustodianProfileImageURL);
182 strings.SetString("avatarURL1x", BuildAvatarImageUrl(profile_image_url,
[email protected]95c47d02014-08-19 09:17:50183 kAvatarSize1x));
184 strings.SetString("avatarURL2x", BuildAvatarImageUrl(profile_image_url,
[email protected]95c47d02014-08-19 09:17:50185 kAvatarSize2x));
186
treibab0a39e2014-09-24 14:48:28187 std::string profile_image_url2 = profile_->GetPrefs()->GetString(
[email protected]95c47d02014-08-19 09:17:50188 prefs::kSupervisedUserSecondCustodianProfileImageURL);
189 strings.SetString("secondAvatarURL1x", BuildAvatarImageUrl(profile_image_url2,
[email protected]95c47d02014-08-19 09:17:50190 kAvatarSize1x));
191 strings.SetString("secondAvatarURL2x", BuildAvatarImageUrl(profile_image_url2,
[email protected]95c47d02014-08-19 09:17:50192 kAvatarSize2x));
193
[email protected]0085863a2013-12-06 21:19:03194 base::string16 custodian =
[email protected]cce15bb2014-06-17 13:43:51195 base::UTF8ToUTF16(supervised_user_service->GetCustodianName());
[email protected]fae057a2013-06-21 22:46:08196 strings.SetString(
197 "blockPageMessage",
[email protected]0369d6ab2013-08-09 01:52:59198 allow_access_requests
199 ? l10n_util::GetStringFUTF16(IDS_BLOCK_INTERSTITIAL_MESSAGE,
200 custodian)
201 : l10n_util::GetStringUTF16(
202 IDS_BLOCK_INTERSTITIAL_MESSAGE_ACCESS_REQUESTS_DISABLED));
[email protected]fae057a2013-06-21 22:46:08203
[email protected]a09159a2012-11-29 12:51:48204 strings.SetString("backButton", l10n_util::GetStringUTF16(IDS_BACK_BUTTON));
205 strings.SetString(
[email protected]59f21562013-05-23 16:19:30206 "requestAccessButton",
207 l10n_util::GetStringUTF16(IDS_BLOCK_INTERSTITIAL_REQUEST_ACCESS_BUTTON));
208
[email protected]59f21562013-05-23 16:19:30209 strings.SetString(
210 "requestSentMessage",
211 l10n_util::GetStringFUTF16(IDS_BLOCK_INTERSTITIAL_REQUEST_SENT_MESSAGE,
[email protected]fae057a2013-06-21 22:46:08212 custodian));
[email protected]59f21562013-05-23 16:19:30213
[email protected]5053d402013-01-23 05:19:26214 webui::SetFontAndTextDirection(&strings);
[email protected]a09159a2012-11-29 12:51:48215
[email protected]0369d6ab2013-08-09 01:52:59216 base::StringPiece html(ResourceBundle::GetSharedInstance().GetRawDataResource(
[email protected]a7340d612014-06-25 22:09:15217 IDR_SUPERVISED_USER_BLOCK_INTERSTITIAL_HTML));
[email protected]a09159a2012-11-29 12:51:48218
[email protected]2779e3a2013-01-22 18:40:21219 webui::UseVersion2 version;
220 return webui::GetI18nTemplateHtml(html, &strings);
[email protected]a09159a2012-11-29 12:51:48221}
222
[email protected]cce15bb2014-06-17 13:43:51223void SupervisedUserInterstitial::CommandReceived(const std::string& command) {
[email protected]2c145422013-01-24 18:15:40224 // For use in histograms.
225 enum Commands {
226 PREVIEW,
227 BACK,
228 NTP,
[email protected]59f21562013-05-23 16:19:30229 ACCESS_REQUEST,
[email protected]2c145422013-01-24 18:15:40230 HISTOGRAM_BOUNDING_VALUE
231 };
232
[email protected]a09159a2012-11-29 12:51:48233 if (command == "\"back\"") {
[email protected]2c145422013-01-24 18:15:40234 UMA_HISTOGRAM_ENUMERATION("ManagedMode.BlockingInterstitialCommand",
235 BACK,
236 HISTOGRAM_BOUNDING_VALUE);
treibe7ccb7e2014-09-09 19:21:45237
238 // Close the tab if there is no history entry to go back to.
239 DCHECK(web_contents_->GetController().GetTransientEntry());
240 if (web_contents_->GetController().GetEntryCount() == 1)
241 TabCloser::CreateForWebContents(web_contents_);
242
[email protected]a09159a2012-11-29 12:51:48243 interstitial_page_->DontProceed();
244 return;
245 }
246
[email protected]59f21562013-05-23 16:19:30247 if (command == "\"request\"") {
[email protected]2c145422013-01-24 18:15:40248 UMA_HISTOGRAM_ENUMERATION("ManagedMode.BlockingInterstitialCommand",
[email protected]59f21562013-05-23 16:19:30249 ACCESS_REQUEST,
[email protected]2c145422013-01-24 18:15:40250 HISTOGRAM_BOUNDING_VALUE);
[email protected]ad7a89e2013-05-31 12:03:24251
[email protected]cce15bb2014-06-17 13:43:51252 SupervisedUserService* supervised_user_service =
treibab0a39e2014-09-24 14:48:28253 SupervisedUserServiceFactory::GetForProfile(profile_);
[email protected]cce15bb2014-06-17 13:43:51254 supervised_user_service->AddAccessRequest(url_);
[email protected]59f21562013-05-23 16:19:30255 DVLOG(1) << "Sent access request for " << url_.spec();
256
[email protected]a09159a2012-11-29 12:51:48257 return;
258 }
259
260 NOTREACHED();
261}
262
[email protected]cce15bb2014-06-17 13:43:51263void SupervisedUserInterstitial::OnProceed() {
[email protected]61f5da22013-09-05 15:52:10264 // CHECK instead of DCHECK as defense in depth in case we'd accidentally
265 // proceed on a blocked page.
266 CHECK(ShouldProceed());
267 DispatchContinueRequest(true);
268}
[email protected]a09159a2012-11-29 12:51:48269
[email protected]cce15bb2014-06-17 13:43:51270void SupervisedUserInterstitial::OnDontProceed() {
[email protected]6c7af96d2013-03-28 22:55:14271 DispatchContinueRequest(false);
[email protected]a09159a2012-11-29 12:51:48272}
273
treibab0a39e2014-09-24 14:48:28274void SupervisedUserInterstitial::OnURLFilterChanged() {
275 if (ShouldProceed())
276 interstitial_page_->Proceed();
277}
278
[email protected]cce15bb2014-06-17 13:43:51279bool SupervisedUserInterstitial::ShouldProceed() {
[email protected]cce15bb2014-06-17 13:43:51280 SupervisedUserService* supervised_user_service =
treibab0a39e2014-09-24 14:48:28281 SupervisedUserServiceFactory::GetForProfile(profile_);
[email protected]cce15bb2014-06-17 13:43:51282 SupervisedUserURLFilter* url_filter =
283 supervised_user_service->GetURLFilterForUIThread();
[email protected]61f5da22013-09-05 15:52:10284 return url_filter->GetFilteringBehaviorForURL(url_) !=
[email protected]cce15bb2014-06-17 13:43:51285 SupervisedUserURLFilter::BLOCK;
[email protected]61f5da22013-09-05 15:52:10286}
287
[email protected]cce15bb2014-06-17 13:43:51288void SupervisedUserInterstitial::DispatchContinueRequest(
289 bool continue_request) {
treibab0a39e2014-09-24 14:48:28290 SupervisedUserService* supervised_user_service =
291 SupervisedUserServiceFactory::GetForProfile(profile_);
292 supervised_user_service->RemoveObserver(this);
293
[email protected]0369d6ab2013-08-09 01:52:59294 BrowserThread::PostTask(
295 BrowserThread::IO, FROM_HERE, base::Bind(callback_, continue_request));
treibab0a39e2014-09-24 14:48:28296
297 // After this, the WebContents may be destroyed. Make sure we don't try to use
298 // it again.
299 web_contents_ = NULL;
[email protected]6c7af96d2013-03-28 22:55:14300}