Commit e8831883 authored by Colin Blundell's avatar Colin Blundell Committed by Chromium LUCI CQ

[WebLayer] Show ads blocked infobar when directed by subresource filter

This CL adds showing of the (now-componentized) ads blocked infobar in
WebLayer. This presentation is made in //weblayer's
SubresourceFilterClientImpl as directed by
//components/subresource_filter. The implementation is adapted from
that of //chrome's ChromeSubresourceFilterClient, but simplified:
- We leave interaction with content settings for followup work
- We do not track whether the infobar has previously been shown for the
  current navigation. The reason is that
  ContentSubresourceFilterThrottleManager already does such tracking
  itself in its MaybeShowNotification() method, so the client should
  never actually receive a duplicate request to show a notification for
  a given navigation.

We also add a browsertest that the infobar is presented when a resource
is blocked and is removed when navigating away from the page with a
blocked resource. Note that while it would be useful to also add tests
in Java, we can't at this time due to crbug.com/899903.

We leave implementation of the reload functionality that the user can
trigger via the infobar for a followup CL.

Bug: 1116095
Change-Id: Icb182143b0d27de5f03efc88ce8013be3c5c91d1
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2563549
Commit-Queue: Colin Blundell <blundell@chromium.org>
Reviewed-by: default avatarCharlie Harrison <csharrison@chromium.org>
Cr-Commit-Position: refs/heads/master@{#833308}
parent 936c3a2e
......@@ -652,6 +652,7 @@ source_set("weblayer_lib_base") {
"//components/security_interstitials/core:unsafe_resource",
"//components/security_interstitials/core/",
"//components/security_state/content/android",
"//components/subresource_filter/android",
"//components/translate/content/android",
"//components/version_info/android:channel_getter",
"//services/resource_coordinator/public/cpp/memory_instrumentation:browser",
......
......@@ -59,6 +59,7 @@ include_rules = [
"+components/ssl_errors",
"+components/startup_metric_utils",
"+components/strings",
"+components/subresource_filter/android",
"+components/subresource_filter/content/browser",
"+components/subresource_filter/core/browser",
"+components/subresource_filter/core/common",
......
......@@ -22,6 +22,12 @@
#include "weblayer/test/weblayer_browser_test.h"
#include "weblayer/test/weblayer_browser_test_utils.h"
#if defined(OS_ANDROID)
#include "components/infobars/android/infobar_android.h" // nogncheck
#include "components/infobars/core/infobar_manager.h" // nogncheck
#include "weblayer/browser/infobar_service.h"
#endif
namespace weblayer {
namespace {
......@@ -37,6 +43,35 @@ bool WasParsedScriptElementLoaded(content::RenderFrameHost* rfh) {
return script_resource_was_loaded;
}
#if defined(OS_ANDROID)
class TestInfoBarManagerObserver : public infobars::InfoBarManager::Observer {
public:
TestInfoBarManagerObserver() = default;
~TestInfoBarManagerObserver() override = default;
void OnInfoBarAdded(infobars::InfoBar* infobar) override {
if (on_infobar_added_callback_)
std::move(on_infobar_added_callback_).Run();
}
void OnInfoBarRemoved(infobars::InfoBar* infobar, bool animate) override {
if (on_infobar_removed_callback_)
std::move(on_infobar_removed_callback_).Run();
}
void set_on_infobar_added_callback(base::OnceClosure callback) {
on_infobar_added_callback_ = std::move(callback);
}
void set_on_infobar_removed_callback(base::OnceClosure callback) {
on_infobar_removed_callback_ = std::move(callback);
}
private:
base::OnceClosure on_infobar_added_callback_;
base::OnceClosure on_infobar_removed_callback_;
};
#endif // if defined(OS_ANDROID)
} // namespace
class SubresourceFilterBrowserTest : public WebLayerBrowserTest {
......@@ -63,6 +98,22 @@ class SubresourceFilterBrowserTest : public WebLayerBrowserTest {
ASSERT_NO_FATAL_FAILURE(
test_ruleset_publisher.SetRuleset(test_ruleset_pair.unindexed));
}
// Configures the database manager to activate on |url| in |web_contents|.
void ActivateSubresourceFilterInWebContentsForURL(
content::WebContents* web_contents,
const GURL& url) {
scoped_refptr<FakeSafeBrowsingDatabaseManager> database_manager =
base::MakeRefCounted<FakeSafeBrowsingDatabaseManager>();
database_manager->AddBlocklistedUrl(
url, safe_browsing::SB_THREAT_TYPE_URL_PHISHING);
auto* client_impl = static_cast<SubresourceFilterClientImpl*>(
subresource_filter::ContentSubresourceFilterThrottleManager::
FromWebContents(web_contents)
->client());
client_impl->set_database_manager_for_testing(std::move(database_manager));
}
};
// Tests that the ruleset service is available.
......@@ -167,16 +218,7 @@ IN_PROC_BROWSER_TEST_F(SubresourceFilterBrowserTest,
observer.GetPageActivation(test_url);
EXPECT_FALSE(page_activation);
// Configure the database manager to activate on this URL.
scoped_refptr<FakeSafeBrowsingDatabaseManager> database_manager =
base::MakeRefCounted<FakeSafeBrowsingDatabaseManager>();
database_manager->AddBlocklistedUrl(
test_url, safe_browsing::SB_THREAT_TYPE_URL_PHISHING);
auto* client_impl = static_cast<SubresourceFilterClientImpl*>(
subresource_filter::ContentSubresourceFilterThrottleManager::
FromWebContents(web_contents)
->client());
client_impl->set_database_manager_for_testing(database_manager);
ActivateSubresourceFilterInWebContentsForURL(web_contents, test_url);
// Verify that the "ad" subframe is loaded if it is not flagged by the
// ruleset.
......@@ -252,4 +294,52 @@ IN_PROC_BROWSER_TEST_F(SubresourceFilterBrowserTest,
EXPECT_TRUE(WasParsedScriptElementLoaded(web_contents->GetMainFrame()));
}
#if defined(OS_ANDROID)
// Test that the ads blocked infobar is presented when visiting a page where the
// subresource filter blocks resources from being loaded and is removed when
// navigating away.
IN_PROC_BROWSER_TEST_F(SubresourceFilterBrowserTest, InfoBarPresentation) {
auto* web_contents = static_cast<TabImpl*>(shell()->tab())->web_contents();
auto* infobar_service = InfoBarService::FromWebContents(web_contents);
// Configure the subresource filter to activate on the test URL and to block
// its script from loading.
GURL test_url(
embedded_test_server()->GetURL("/frame_with_included_script.html"));
ActivateSubresourceFilterInWebContentsForURL(web_contents, test_url);
ASSERT_NO_FATAL_FAILURE(
SetRulesetToDisallowURLsWithPathSuffix("included_script.js"));
TestInfoBarManagerObserver infobar_observer;
infobar_service->AddObserver(&infobar_observer);
base::RunLoop run_loop;
infobar_observer.set_on_infobar_added_callback(run_loop.QuitClosure());
EXPECT_EQ(0u, infobar_service->infobar_count());
// Navigate such that the script is blocked and verify that the ads blocked
// infobar is presented.
NavigateAndWaitForCompletion(test_url, shell());
run_loop.Run();
EXPECT_EQ(1u, infobar_service->infobar_count());
auto* infobar =
static_cast<infobars::InfoBarAndroid*>(infobar_service->infobar_at(0));
EXPECT_TRUE(infobar->HasSetJavaInfoBar());
EXPECT_EQ(infobar->delegate()->GetIdentifier(),
infobars::InfoBarDelegate::ADS_BLOCKED_INFOBAR_DELEGATE_ANDROID);
// Navigate away and verify that the infobar is removed.
base::RunLoop run_loop2;
infobar_observer.set_on_infobar_removed_callback(run_loop2.QuitClosure());
NavigateAndWaitForCompletion(GURL("about:blank"), shell());
run_loop2.Run();
EXPECT_EQ(0u, infobar_service->infobar_count());
infobar_service->RemoveObserver(&infobar_observer);
}
#endif
} // namespace weblayer
......@@ -21,6 +21,8 @@
#if defined(OS_ANDROID)
#include "components/safe_browsing/android/remote_database_manager.h"
#include "components/subresource_filter/android/ads_blocked_infobar_delegate.h"
#include "weblayer/browser/infobar_service.h"
#endif
namespace weblayer {
......@@ -45,8 +47,14 @@ GetDatabaseManagerFromSafeBrowsingService() {
} // namespace
SubresourceFilterClientImpl::SubresourceFilterClientImpl()
: database_manager_(GetDatabaseManagerFromSafeBrowsingService()) {}
SubresourceFilterClientImpl::SubresourceFilterClientImpl(
content::WebContents* web_contents)
:
#if defined(OS_ANDROID)
web_contents_(web_contents),
#endif
database_manager_(GetDatabaseManagerFromSafeBrowsingService()) {
}
SubresourceFilterClientImpl::~SubresourceFilterClientImpl() = default;
......@@ -58,19 +66,27 @@ void SubresourceFilterClientImpl::CreateThrottleManagerWithClientForWebContents(
subresource_filter::VerifiedRulesetDealer::Handle* dealer =
ruleset_service ? ruleset_service->GetRulesetDealer() : nullptr;
subresource_filter::ContentSubresourceFilterThrottleManager::
CreateForWebContents(web_contents,
std::make_unique<SubresourceFilterClientImpl>(),
dealer);
CreateForWebContents(
web_contents,
std::make_unique<SubresourceFilterClientImpl>(web_contents), dealer);
}
void SubresourceFilterClientImpl::OnReloadRequested() {
// TODO(crbug.com/1116095): Bring up this flow on Android when user requests
// it via the infobar.
NOTREACHED();
NOTIMPLEMENTED();
}
void SubresourceFilterClientImpl::ShowNotification() {
// TODO(crbug.com/1116095): Show infobar on Android.
#if defined(OS_ANDROID)
// TODO(crbug.com/1116095): Move ChromeSubresourceFilterClient::ShowUI()'s
// interaction with metrics and content settings into code that's shared by
// WebLayer.
InfoBarService* infobar_service =
InfoBarService::FromWebContents(web_contents_);
subresource_filter::AdsBlockedInfobarDelegate::Create(
infobar_service, InfoBarService::GetResourceIdMapper());
#endif
}
subresource_filter::mojom::ActivationLevel
......
......@@ -8,6 +8,7 @@
#include <memory>
#include <utility>
#include "build/build_config.h"
#include "components/safe_browsing/core/db/database_manager.h"
#include "components/subresource_filter/content/browser/subresource_filter_client.h"
#include "url/gurl.h"
......@@ -27,7 +28,7 @@ namespace weblayer {
class SubresourceFilterClientImpl
: public subresource_filter::SubresourceFilterClient {
public:
SubresourceFilterClientImpl();
explicit SubresourceFilterClientImpl(content::WebContents* web_contents);
~SubresourceFilterClientImpl() override;
SubresourceFilterClientImpl(const SubresourceFilterClientImpl&) = delete;
......@@ -61,6 +62,11 @@ class SubresourceFilterClientImpl
}
private:
// This member is only used on Android, so it's necessary to ifdef it to avoid
// a compiler error on other platforms.
#if defined(OS_ANDROID)
content::WebContents* web_contents_;
#endif
std::unique_ptr<subresource_filter::ContentSubresourceFilterThrottleManager>
throttle_manager_;
scoped_refptr<safe_browsing::SafeBrowsingDatabaseManager> database_manager_;
......
IDR_ANDROID_INFOBAR_BLOCKED_POPUPS
IDR_SAD_PLUGIN
IDR_SAD_WEBVIEW
IDR_SSL_ERROR_ASSISTANT_PB
......
IDS_OK
IDS_RELOAD
IDS_BLOCKED_ADS_PROMPT_EXPLANATION
IDS_ALWAYS_ALLOW_ADS
IDS_BLOCKED_ADS_INFOBAR_MESSAGE
IDS_ACCESSIBILITY_EVENTS_INFOBAR_TEXT
IDS_ACCESSIBILITY_EVENTS_PERMISSION_FRAGMENT
IDS_AR_AND_MEDIA_CAPTURE_VIDEO_INFOBAR_TEXT
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment