blob: daa342f0cf16de2a43d212a749e19e7173e5a099 [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 }
dchengc072fff2014-10-21 11:39:0568 ~TabCloser() override {}
treibe7ccb7e2014-09-09 19:21:4569
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),
bauerb646019b12014-10-16 16:23:09117 callback_(callback),
118 weak_ptr_factory_(this) {}
[email protected]b8af2d12014-04-29 07:30:42119
treibab0a39e2014-09-24 14:48:28120SupervisedUserInterstitial::~SupervisedUserInterstitial() {
121 DCHECK(!web_contents_);
122}
[email protected]b8af2d12014-04-29 07:30:42123
[email protected]cce15bb2014-06-17 13:43:51124bool SupervisedUserInterstitial::Init() {
[email protected]61f5da22013-09-05 15:52:10125 if (ShouldProceed()) {
126 // It can happen that the site was only allowed very recently and the URL
127 // filter on the IO thread had not been updated yet. Proceed with the
128 // request without showing the interstitial.
129 DispatchContinueRequest(true);
[email protected]b8af2d12014-04-29 07:30:42130 return false;
[email protected]61f5da22013-09-05 15:52:10131 }
132
[email protected]b8af2d12014-04-29 07:30:42133 InfoBarService* service = InfoBarService::FromWebContents(web_contents_);
[email protected]93c23212013-09-19 14:22:38134 if (service) {
[email protected]b8af2d12014-04-29 07:30:42135 // Remove all the infobars which are attached to |web_contents_| and for
[email protected]93c23212013-09-19 14:22:38136 // which ShouldExpire() returns true.
137 content::LoadCommittedDetails details;
138 // |details.is_in_page| is default false, and |details.is_main_frame| is
139 // default true. This results in is_navigation_to_different_page() returning
140 // true.
141 DCHECK(details.is_navigation_to_different_page());
142 const content::NavigationController& controller =
[email protected]b8af2d12014-04-29 07:30:42143 web_contents_->GetController();
[email protected]93c23212013-09-19 14:22:38144 details.entry = controller.GetActiveEntry();
145 if (controller.GetLastCommittedEntry()) {
146 details.previous_entry_index = controller.GetLastCommittedEntryIndex();
147 details.previous_url = controller.GetLastCommittedEntry()->GetURL();
148 }
149 details.type = content::NAVIGATION_TYPE_NEW_PAGE;
[email protected]b44f1d32014-04-10 13:53:26150 for (int i = service->infobar_count() - 1; i >= 0; --i) {
[email protected]051655ad2014-04-18 15:09:41151 infobars::InfoBar* infobar = service->infobar_at(i);
[email protected]5daf1d92014-04-04 15:52:13152 if (infobar->delegate()->ShouldExpire(
153 InfoBarService::NavigationDetailsFromLoadCommittedDetails(
154 details)))
[email protected]b44f1d32014-04-10 13:53:26155 service->RemoveInfoBar(infobar);
[email protected]93c23212013-09-19 14:22:38156 }
157 }
158
treibab0a39e2014-09-24 14:48:28159 SupervisedUserService* supervised_user_service =
160 SupervisedUserServiceFactory::GetForProfile(profile_);
161 supervised_user_service->AddObserver(this);
[email protected]a09159a2012-11-29 12:51:48162
[email protected]0369d6ab2013-08-09 01:52:59163 interstitial_page_ =
[email protected]b8af2d12014-04-29 07:30:42164 content::InterstitialPage::Create(web_contents_, true, url_, this);
[email protected]a09159a2012-11-29 12:51:48165 interstitial_page_->Show();
[email protected]a09159a2012-11-29 12:51:48166
[email protected]b8af2d12014-04-29 07:30:42167 return true;
168}
[email protected]a09159a2012-11-29 12:51:48169
[email protected]cce15bb2014-06-17 13:43:51170std::string SupervisedUserInterstitial::GetHTMLContents() {
[email protected]cb1078de2013-12-23 20:04:22171 base::DictionaryValue strings;
[email protected]a09159a2012-11-29 12:51:48172 strings.SetString("blockPageTitle",
173 l10n_util::GetStringUTF16(IDS_BLOCK_INTERSTITIAL_TITLE));
[email protected]fae057a2013-06-21 22:46:08174
[email protected]cce15bb2014-06-17 13:43:51175 SupervisedUserService* supervised_user_service =
treibab0a39e2014-09-24 14:48:28176 SupervisedUserServiceFactory::GetForProfile(profile_);
[email protected]0369d6ab2013-08-09 01:52:59177
[email protected]cce15bb2014-06-17 13:43:51178 bool allow_access_requests = supervised_user_service->AccessRequestsEnabled();
[email protected]0369d6ab2013-08-09 01:52:59179 strings.SetBoolean("allowAccessRequests", allow_access_requests);
180
treibab0a39e2014-09-24 14:48:28181 std::string profile_image_url = profile_->GetPrefs()->GetString(
[email protected]95c47d02014-08-19 09:17:50182 prefs::kSupervisedUserCustodianProfileImageURL);
183 strings.SetString("avatarURL1x", BuildAvatarImageUrl(profile_image_url,
[email protected]95c47d02014-08-19 09:17:50184 kAvatarSize1x));
185 strings.SetString("avatarURL2x", BuildAvatarImageUrl(profile_image_url,
[email protected]95c47d02014-08-19 09:17:50186 kAvatarSize2x));
187
treibab0a39e2014-09-24 14:48:28188 std::string profile_image_url2 = profile_->GetPrefs()->GetString(
[email protected]95c47d02014-08-19 09:17:50189 prefs::kSupervisedUserSecondCustodianProfileImageURL);
190 strings.SetString("secondAvatarURL1x", BuildAvatarImageUrl(profile_image_url2,
[email protected]95c47d02014-08-19 09:17:50191 kAvatarSize1x));
192 strings.SetString("secondAvatarURL2x", BuildAvatarImageUrl(profile_image_url2,
[email protected]95c47d02014-08-19 09:17:50193 kAvatarSize2x));
194
[email protected]0085863a2013-12-06 21:19:03195 base::string16 custodian =
[email protected]cce15bb2014-06-17 13:43:51196 base::UTF8ToUTF16(supervised_user_service->GetCustodianName());
[email protected]fae057a2013-06-21 22:46:08197 strings.SetString(
198 "blockPageMessage",
[email protected]0369d6ab2013-08-09 01:52:59199 allow_access_requests
200 ? l10n_util::GetStringFUTF16(IDS_BLOCK_INTERSTITIAL_MESSAGE,
201 custodian)
202 : l10n_util::GetStringUTF16(
203 IDS_BLOCK_INTERSTITIAL_MESSAGE_ACCESS_REQUESTS_DISABLED));
[email protected]fae057a2013-06-21 22:46:08204
[email protected]a09159a2012-11-29 12:51:48205 strings.SetString("backButton", l10n_util::GetStringUTF16(IDS_BACK_BUTTON));
206 strings.SetString(
[email protected]59f21562013-05-23 16:19:30207 "requestAccessButton",
208 l10n_util::GetStringUTF16(IDS_BLOCK_INTERSTITIAL_REQUEST_ACCESS_BUTTON));
209
[email protected]59f21562013-05-23 16:19:30210 strings.SetString(
211 "requestSentMessage",
212 l10n_util::GetStringFUTF16(IDS_BLOCK_INTERSTITIAL_REQUEST_SENT_MESSAGE,
[email protected]fae057a2013-06-21 22:46:08213 custodian));
[email protected]59f21562013-05-23 16:19:30214
[email protected]5053d402013-01-23 05:19:26215 webui::SetFontAndTextDirection(&strings);
[email protected]a09159a2012-11-29 12:51:48216
[email protected]0369d6ab2013-08-09 01:52:59217 base::StringPiece html(ResourceBundle::GetSharedInstance().GetRawDataResource(
[email protected]a7340d612014-06-25 22:09:15218 IDR_SUPERVISED_USER_BLOCK_INTERSTITIAL_HTML));
[email protected]a09159a2012-11-29 12:51:48219
[email protected]2779e3a2013-01-22 18:40:21220 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_);
bauerb646019b12014-10-16 16:23:09254 supervised_user_service->AddAccessRequest(
255 url_, base::Bind(&SupervisedUserInterstitial::OnAccessRequestAdded,
256 weak_ptr_factory_.GetWeakPtr()));
[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 DispatchContinueRequest(true);
265}
[email protected]a09159a2012-11-29 12:51:48266
[email protected]cce15bb2014-06-17 13:43:51267void SupervisedUserInterstitial::OnDontProceed() {
[email protected]6c7af96d2013-03-28 22:55:14268 DispatchContinueRequest(false);
[email protected]a09159a2012-11-29 12:51:48269}
270
treibab0a39e2014-09-24 14:48:28271void SupervisedUserInterstitial::OnURLFilterChanged() {
272 if (ShouldProceed())
273 interstitial_page_->Proceed();
274}
275
bauerb646019b12014-10-16 16:23:09276void SupervisedUserInterstitial::OnAccessRequestAdded(bool success) {
277 // TODO(akuegel): Figure out how to show the result of issuing the permission
278 // request in the UI. Currently, we assume the permission request was created
279 // successfully.
280 DVLOG(1) << "Sent access request for " << url_.spec()
281 << (success ? " successfully" : " unsuccessfully");
282}
283
[email protected]cce15bb2014-06-17 13:43:51284bool SupervisedUserInterstitial::ShouldProceed() {
[email protected]cce15bb2014-06-17 13:43:51285 SupervisedUserService* supervised_user_service =
treibab0a39e2014-09-24 14:48:28286 SupervisedUserServiceFactory::GetForProfile(profile_);
[email protected]cce15bb2014-06-17 13:43:51287 SupervisedUserURLFilter* url_filter =
288 supervised_user_service->GetURLFilterForUIThread();
treib9e4fab902014-10-29 14:25:26289 SupervisedUserURLFilter::FilteringBehavior behavior;
290 return (url_filter->GetManualFilteringBehaviorForURL(url_, &behavior) &&
291 behavior != SupervisedUserURLFilter::BLOCK);
[email protected]61f5da22013-09-05 15:52:10292}
293
[email protected]cce15bb2014-06-17 13:43:51294void SupervisedUserInterstitial::DispatchContinueRequest(
295 bool continue_request) {
treibab0a39e2014-09-24 14:48:28296 SupervisedUserService* supervised_user_service =
297 SupervisedUserServiceFactory::GetForProfile(profile_);
298 supervised_user_service->RemoveObserver(this);
299
[email protected]0369d6ab2013-08-09 01:52:59300 BrowserThread::PostTask(
301 BrowserThread::IO, FROM_HERE, base::Bind(callback_, continue_request));
treibab0a39e2014-09-24 14:48:28302
303 // After this, the WebContents may be destroyed. Make sure we don't try to use
304 // it again.
305 web_contents_ = NULL;
[email protected]6c7af96d2013-03-28 22:55:14306}