Commit 10087e04 authored by Christian Dullweber's avatar Christian Dullweber Committed by Commit Bot

Add page action icon for cookie controls

Add a page action icon and a bubble view to control third-party
cookie blocking. Replaces the "Cookies blocked" icon when enabled.

https://screenshot.googleplex.com/3jFhD5uJj1W.png

Bug: 967668
Change-Id: Id498f3f569ef940d1cb277dc8ea629c7de329cfd
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/1685382
Commit-Queue: Christian Dullweber <dullweber@chromium.org>
Reviewed-by: default avatarEvan Stade <estade@chromium.org>
Reviewed-by: default avatarMitsuru Oshima <oshima@chromium.org>
Reviewed-by: default avatarKen Rockot <rockot@google.com>
Reviewed-by: default avatarElly Fong-Jones <ellyjones@chromium.org>
Reviewed-by: default avatarKevin Bailey <krb@chromium.org>
Cr-Commit-Position: refs/heads/master@{#691116}
parent 38262236
......@@ -2480,6 +2480,29 @@ are declared in tools/grit/grit_rule.gni.
Allow for this site
</message>
<!-- Cookie controls strings. -->
<message name="IDS_COOKIE_CONTROLS_DIALOG_TITLE" desc="Title of the dialog that allows users to control cookie blocking.">
Tracking protection is on
</message>
<message name="IDS_COOKIE_CONTROLS_DIALOG_TITLE_OFF" desc="Text shown in the dialog that allows users to control cookie blocking. Shown when cookie blocking was disabled for this specific site.">
Tracking protection is turned off for this site
</message>
<message name="IDS_COOKIE_CONTROLS_TURN_ON_BUTTON" desc="Label shown on a button that turns cookie blocking on after it was disabled for a specific site.">
Turn on
</message>
<message name="IDS_COOKIE_CONTROLS_TURN_OFF_BUTTON" desc="Label shown on a button that turns of cookie blocking for a specific site.">
Turn off for this site
</message>
<message name="IDS_COOKIE_CONTROLS_BLOCKED_MESSAGE" desc="Text shown in the dialog that allows users to control cookie blocking. Shows the number of sites for which cookies have been blocked.">
{COUNT, plural,
=0 {This site doesn't use cookies for cross-site tracking}
=1 {Chrome is blocking cookies from 1 site}
other {Chrome is blocking cookies from # sites}}
</message>
<message name="IDS_COOKIE_CONTROLS_TOOLTIP" desc="Tooltip shown on a page action icon that is shown when cookie blocking is enabled.">
Tracking protection
</message>
<!-- Win certificate selector dialog strings. -->
<if expr="toolkit_views">
<message name="IDS_CERT_SELECTOR_SUBJECT_COLUMN" desc="The text of the header for the certificate subject column in the certificate selector dialog.">
......
......@@ -275,6 +275,11 @@
<if expr="chromeos">
<structure type="chrome_scaled_image" name="IDR_TAB_RECORDING_INDICATOR" file="cros/tab_recording_indicator.png" />
</if>
<if expr="not is_android">
<structure type="chrome_scaled_image" name="IDR_COOKIE_BLOCKING_ON_HEADER" file="common/cookie_blocking_on_header.png" />
<structure type="chrome_scaled_image" name="IDR_COOKIE_BLOCKING_INACTIVE_HEADER" file="common/cookie_blocking_inactive_header.png" />
<structure type="chrome_scaled_image" name="IDR_COOKIE_BLOCKING_OFF_HEADER" file="common/cookie_blocking_off_header.png" />
</if>
<structure type="chrome_scaled_image" name="IDR_TAB_DROP_DOWN" file="tab_drop_down.png" />
<structure type="chrome_scaled_image" name="IDR_TAB_DROP_UP" file="tab_drop_up.png" />
<structure type="chrome_scaled_image" name="IDR_THEME_BUTTON_BACKGROUND" file="notused.png" />
......
......@@ -85,6 +85,8 @@ aggregate_vector_icons("chrome_vector_icons") {
"save_original_file.icon",
"security.icon",
"send_tab_to_self.icon",
"shield_off.icon",
"shield_outline.icon",
"sensors.icon",
"signin_button_drop_down_arrow.icon",
"sign_out.icon",
......
// Copyright 2019 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
CANVAS_DIMENSIONS, 16,
MOVE_TO, 11.51f, 13.07f,
CUBIC_TO, 10.54f, 14, 9.33f, 14.69f, 8, 15,
CUBIC_TO, 4.56f, 14.2f, 2, 10.9f, 2, 7.36f,
LINE_TO, 2, 3.56f,
LINE_TO, 1.1f, 2.66f,
LINE_TO, 2.16f, 1.6f,
LINE_TO, 14.18f, 13.62f,
LINE_TO, 13.12f, 14.68f,
LINE_TO, 11.51f, 13.07f,
CLOSE,
MOVE_TO, 3.33f, 4.89f,
LINE_TO, 3.33f, 7.36f,
CUBIC_TO, 3.33f, 10.24f, 5.32f, 12.89f, 8, 13.68f,
CUBIC_TO, 8.98f, 13.39f, 9.86f, 12.86f, 10.59f, 12.15f,
LINE_TO, 3.33f, 4.89f,
CLOSE,
MOVE_TO, 13.29f, 10.57f,
LINE_TO, 12.28f, 9.56f,
CUBIC_TO, 12.53f, 8.86f, 12.67f, 8.12f, 12.67f, 7.36f,
LINE_TO, 12.67f, 4.37f,
LINE_TO, 8, 2.39f,
LINE_TO, 5.97f, 3.25f,
LINE_TO, 5, 2.27f,
LINE_TO, 8, 1,
LINE_TO, 14, 3.55f,
LINE_TO, 14, 7.36f,
CUBIC_TO, 14, 8.48f, 13.75f, 9.57f, 13.29f, 10.57f,
CLOSE
// Copyright 2019 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
CANVAS_DIMENSIONS, 16,
MOVE_TO, 8, 0.67f,
LINE_TO, 2, 3.33f,
R_V_LINE_TO, 4,
R_CUBIC_TO, 0, 3.7f, 2.56f, 7.16f, 6, 8,
R_CUBIC_TO, 3.44f, -0.84f, 6, -4.3f, 6, -8,
R_V_LINE_TO, -4,
LINE_TO, 8, 0.67f,
CLOSE,
R_MOVE_TO, 4.67f, 6.67f,
R_CUBIC_TO, 0, 3.01f, -1.99f, 5.79f, -4.67f, 6.62f,
R_CUBIC_TO, -2.68f, -0.83f, -4.67f, -3.61f, -4.67f, -6.62f,
V_LINE_TO, 4.2f,
LINE_TO, 8, 2.13f,
LINE_TO, 12.67f, 4.2f,
R_V_LINE_TO, 3.13f,
CLOSE
\ No newline at end of file
......@@ -2524,6 +2524,9 @@ jumbo_split_static_library("ui") {
"autofill/payments/save_card_bubble_view.h",
"autofill/payments/save_card_ui.h",
"bubble_anchor_util.h",
"cookie_controls/cookie_controls_controller.cc",
"cookie_controls/cookie_controls_controller.h",
"cookie_controls/cookie_controls_view.h",
"manifest_web_app_browser_controller.cc",
"manifest_web_app_browser_controller.h",
"send_tab_to_self/send_tab_to_self_bubble_controller.cc",
......@@ -2800,6 +2803,10 @@ jumbo_split_static_library("ui") {
"views/load_complete_listener.h",
"views/location_bar/content_setting_image_view.cc",
"views/location_bar/content_setting_image_view.h",
"views/location_bar/cookie_controls_bubble_view.cc",
"views/location_bar/cookie_controls_bubble_view.h",
"views/location_bar/cookie_controls_icon_view.cc",
"views/location_bar/cookie_controls_icon_view.h",
"views/location_bar/custom_tab_bar_view.cc",
"views/location_bar/custom_tab_bar_view.h",
"views/location_bar/find_bar_icon.cc",
......
......@@ -246,6 +246,7 @@ enum class DialogIdentifier {
INCOGNITO_WINDOW_COUNT = 92,
CROSTINI_APP_UNINSTALLER = 93,
CROSTINI_CONTAINER_UPGRADE = 94,
COOKIE_CONTROLS = 95,
// Add values above this line with a corresponding label in
// tools/metrics/histograms/enums.xml
MAX_VALUE
......
......@@ -13,6 +13,7 @@
#include "build/build_config.h"
#include "chrome/app/vector_icons/vector_icons.h"
#include "chrome/browser/browser_process.h"
#include "chrome/browser/content_settings/cookie_settings_factory.h"
#include "chrome/browser/content_settings/host_content_settings_map_factory.h"
#include "chrome/browser/content_settings/tab_specific_content_settings.h"
#include "chrome/browser/download/download_request_limiter.h"
......@@ -24,7 +25,11 @@
#include "chrome/common/chrome_features.h"
#include "chrome/grit/chromium_strings.h"
#include "chrome/grit/generated_resources.h"
#include "components/content_settings/core/browser/cookie_settings.h"
#include "components/content_settings/core/browser/host_content_settings_map.h"
#include "components/content_settings/core/common/content_settings_types.h"
#include "components/content_settings/core/common/features.h"
#include "components/prefs/pref_service.h"
#include "components/vector_icons/vector_icons.h"
#include "content/public/browser/web_contents.h"
#include "services/device/public/cpp/device_features.h"
......@@ -335,8 +340,9 @@ bool ContentSettingBlockedImageModel::UpdateAndGetVisibility(
if (!is_blocked && !is_allowed)
return false;
HostContentSettingsMap* map = HostContentSettingsMapFactory::GetForProfile(
Profile::FromBrowserContext(web_contents->GetBrowserContext()));
Profile* profile =
Profile::FromBrowserContext(web_contents->GetBrowserContext());
auto* map = HostContentSettingsMapFactory::GetForProfile(profile);
// For allowed cookies, don't show the cookie page action unless cookies are
// blocked by default.
......@@ -345,6 +351,12 @@ bool ContentSettingBlockedImageModel::UpdateAndGetVisibility(
return false;
}
if (type == CONTENT_SETTINGS_TYPE_COOKIES &&
CookieSettingsFactory::GetForProfile(profile)
->IsCookieControlsEnabled()) {
return false;
}
if (!is_blocked) {
tooltip_id = image_details->accessed_tooltip_id;
explanation_id = 0;
......
// Copyright 2019 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "chrome/browser/ui/cookie_controls/cookie_controls_controller.h"
#include <memory>
#include "base/bind.h"
#include "chrome/browser/content_settings/cookie_settings_factory.h"
#include "chrome/browser/content_settings/local_shared_objects_container.h"
#include "chrome/browser/content_settings/tab_specific_content_settings.h"
#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/ui/cookie_controls/cookie_controls_view.h"
#include "components/content_settings/core/browser/cookie_settings.h"
#include "components/content_settings/core/common/pref_names.h"
#include "components/prefs/pref_service.h"
#include "content/public/browser/reload_type.h"
#include "content/public/browser/web_contents.h"
#include "content/public/common/url_constants.h"
#include "extensions/common/constants.h"
CookieControlsController::CookieControlsController(
content::WebContents* web_contents) {
DCHECK(web_contents);
Profile* profile =
Profile::FromBrowserContext(web_contents->GetBrowserContext());
cookie_settings_ = CookieSettingsFactory::GetForProfile(profile);
pref_change_registrar_.Init(profile->GetPrefs());
pref_change_registrar_.Add(
prefs::kCookieControlsMode,
base::BindRepeating(
&CookieControlsController::OnCookieControlsPrefChanged,
base::Unretained(this)));
}
CookieControlsController::~CookieControlsController() {}
void CookieControlsController::OnBubbleUiClosing(
content::WebContents* web_contents) {
if (should_reload_ && web_contents && !web_contents->IsBeingDestroyed())
web_contents->GetController().Reload(content::ReloadType::NORMAL, true);
should_reload_ = false;
}
void CookieControlsController::Update(content::WebContents* web_contents) {
DCHECK(web_contents);
if (!tab_observer_ || GetWebContents() != web_contents) {
DCHECK(TabSpecificContentSettings::FromWebContents(web_contents));
tab_observer_ = std::make_unique<TabObserver>(
this, TabSpecificContentSettings::FromWebContents(web_contents));
}
for (auto& observer : observers_)
observer.OnStatusChanged(GetStatus(web_contents));
PresentBlockedCookieCounter();
}
CookieControlsController::Status CookieControlsController::GetStatus(
content::WebContents* web_contents) {
if (!cookie_settings_->IsCookieControlsEnabled())
return CookieControlsController::Status::kDisabled;
const GURL& url = web_contents->GetURL();
if (url.SchemeIs(content::kChromeUIScheme) ||
url.SchemeIs(extensions::kExtensionScheme)) {
return CookieControlsController::Status::kDisabled;
}
return cookie_settings_->IsThirdPartyAccessAllowed(web_contents->GetURL())
? CookieControlsController::Status::kDisabledForSite
: CookieControlsController::Status::kEnabled;
}
void CookieControlsController::OnCookieBlockingEnabledForSite(
bool block_third_party_cookies) {
if (block_third_party_cookies) {
should_reload_ = false;
cookie_settings_->ResetThirdPartyCookieSetting(GetWebContents()->GetURL());
} else {
should_reload_ = true;
cookie_settings_->SetThirdPartyCookieSetting(
GetWebContents()->GetURL(), ContentSetting::CONTENT_SETTING_ALLOW);
}
Update(GetWebContents());
}
int CookieControlsController::GetBlockedDomainCount() {
const LocalSharedObjectsContainer& blocked_objects =
tab_observer_->tab_specific_content_settings()
->blocked_local_shared_objects();
return blocked_objects.GetDomainCount();
}
void CookieControlsController::PresentBlockedCookieCounter() {
const LocalSharedObjectsContainer& blocked_objects =
tab_observer_->tab_specific_content_settings()
->blocked_local_shared_objects();
for (auto& observer : observers_)
observer.OnBlockedCookiesCountChanged(blocked_objects.GetObjectCount());
}
void CookieControlsController::OnCookieControlsPrefChanged() {
if (GetWebContents())
Update(GetWebContents());
}
content::WebContents* CookieControlsController::GetWebContents() {
if (!tab_observer_)
return nullptr;
return tab_observer_->tab_specific_content_settings()->web_contents();
}
void CookieControlsController::AddObserver(CookieControlsView* obs) {
observers_.AddObserver(obs);
}
void CookieControlsController::RemoveObserver(const CookieControlsView* obs) {
observers_.RemoveObserver(obs);
}
CookieControlsController::TabObserver::TabObserver(
CookieControlsController* cookie_controls,
TabSpecificContentSettings* tab_specific_content_settings)
: TabSpecificContentSettings::SiteDataObserver(
tab_specific_content_settings),
cookie_controls_(cookie_controls) {}
void CookieControlsController::TabObserver::OnSiteDataAccessed() {
cookie_controls_->PresentBlockedCookieCounter();
}
// Copyright 2019 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef CHROME_BROWSER_UI_COOKIE_CONTROLS_COOKIE_CONTROLS_CONTROLLER_H_
#define CHROME_BROWSER_UI_COOKIE_CONTROLS_COOKIE_CONTROLS_CONTROLLER_H_
#include "base/memory/scoped_refptr.h"
#include "base/observer_list.h"
#include "chrome/browser/content_settings/tab_specific_content_settings.h"
#include "components/prefs/pref_change_registrar.h"
#include "content/public/browser/web_contents.h"
namespace content {
class WebContents;
}
namespace content_settings {
class CookieSettings;
}
class CookieControlsView;
// A controller for CookieControlsIconView and CookieControlsBubbleView.
class CookieControlsController {
public:
enum class Status {
kUninitialized,
kEnabled,
kDisabled,
kDisabledForSite,
};
explicit CookieControlsController(content::WebContents* web_contents);
~CookieControlsController();
// Called when the web_contents has changed.
void Update(content::WebContents* web_contents);
// Called when CookieControlsBubbleView is closing.
void OnBubbleUiClosing(content::WebContents* web_contents);
// Called when the user clicks on the button to enable/disable cookie
// blocking.
void OnCookieBlockingEnabledForSite(bool block_third_party_cookies);
// Returns the number of registrable domains with blocked cookies.
int GetBlockedDomainCount();
void AddObserver(CookieControlsView* obs);
void RemoveObserver(const CookieControlsView* obs);
private:
// The observed WebContents changes during the lifetime of the
// CookieControlsController. SiteDataObserver can't change the observed
// object, so we need an inner class that can be recreated when necessary.
// TODO(dullweber): Make it possible to change the observed class and maybe
// convert SiteDataObserver to a pure virtual interface.
class TabObserver : public TabSpecificContentSettings::SiteDataObserver {
public:
TabObserver(CookieControlsController* cookie_controls,
TabSpecificContentSettings* tab_specific_content_settings);
// TabSpecificContentSettings::SiteDataObserver:
void OnSiteDataAccessed() override;
private:
CookieControlsController* cookie_controls_;
DISALLOW_COPY_AND_ASSIGN(TabObserver);
};
// Determine the CookieControlsController::Status based on |web_contents|.
Status GetStatus(content::WebContents* web_contents);
// Updates the blocked cookie count of |icon_|.
void PresentBlockedCookieCounter();
// Callback for when the cookie controls preference changes.
void OnCookieControlsPrefChanged();
content::WebContents* GetWebContents();
std::unique_ptr<TabObserver> tab_observer_;
scoped_refptr<content_settings::CookieSettings> cookie_settings_;
PrefChangeRegistrar pref_change_registrar_;
bool should_reload_ = false;
base::ObserverList<CookieControlsView> observers_;
DISALLOW_COPY_AND_ASSIGN(CookieControlsController);
};
#endif // CHROME_BROWSER_UI_COOKIE_CONTROLS_COOKIE_CONTROLS_CONTROLLER_H_
// Copyright 2019 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "chrome/browser/ui/cookie_controls/cookie_controls_controller.h"
#include "base/test/scoped_feature_list.h"
#include "chrome/browser/content_settings/tab_specific_content_settings.h"
#include "chrome/browser/ui/cookie_controls/cookie_controls_view.h"
#include "chrome/test/base/chrome_render_view_host_test_harness.h"
#include "chrome/test/base/testing_profile.h"
#include "components/content_settings/core/browser/cookie_settings.h"
#include "components/content_settings/core/common/features.h"
#include "components/content_settings/core/common/pref_names.h"
#include "components/prefs/pref_service.h"
#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
namespace {
class MockCookieControlsView : public CookieControlsView {
public:
MOCK_METHOD1(OnStatusChanged, void(CookieControlsController::Status));
MOCK_METHOD1(OnBlockedCookiesCountChanged, void(int));
};
} // namespace
// More readable output for test expectation.
std::ostream& operator<<(std::ostream& os,
const CookieControlsController::Status& status) {
switch (status) {
case CookieControlsController::Status::kDisabled:
return os << "kDisabled";
case CookieControlsController::Status::kEnabled:
return os << "kEnabled";
case CookieControlsController::Status::kDisabledForSite:
return os << "kDisabledForSite";
case CookieControlsController::Status::kUninitialized:
return os << "kUninitialized";
}
}
class CookieControlsTest : public ChromeRenderViewHostTestHarness {
protected:
void SetUp() override {
feature_list.InitAndEnableFeature(
content_settings::kImprovedCookieControls);
ChromeRenderViewHostTestHarness::SetUp();
TabSpecificContentSettings::CreateForWebContents(web_contents());
profile()->GetPrefs()->SetInteger(
prefs::kCookieControlsMode,
static_cast<int>(content_settings::CookieControlsMode::kOn));
NavigateAndCommit(GURL("chrome://new-tab"));
cookie_controls_ =
std::make_unique<CookieControlsController>(web_contents());
cookie_controls_->AddObserver(mock());
testing::Mock::VerifyAndClearExpectations(mock());
}
void TearDown() override {
cookie_controls_->RemoveObserver(mock());
cookie_controls_.reset();
ChromeRenderViewHostTestHarness::TearDown();
}
CookieControlsController* cookie_controls() { return cookie_controls_.get(); }
MockCookieControlsView* mock() { return &mock_; }
TabSpecificContentSettings* tab_specific_content_settings() {
return TabSpecificContentSettings::FromWebContents(web_contents());
}
private:
base::test::ScopedFeatureList feature_list;
MockCookieControlsView mock_;
std::unique_ptr<CookieControlsController> cookie_controls_;
};
TEST_F(CookieControlsTest, NewTabPage) {
EXPECT_CALL(*mock(),
OnStatusChanged(CookieControlsController::Status::kDisabled));
EXPECT_CALL(*mock(), OnBlockedCookiesCountChanged(0));
cookie_controls()->Update(web_contents());
}
TEST_F(CookieControlsTest, SomeWebSite) {
// Visiting a website should enable the UI.
NavigateAndCommit(GURL("https://example.com"));
EXPECT_CALL(*mock(),
OnStatusChanged(CookieControlsController::Status::kEnabled));
EXPECT_CALL(*mock(), OnBlockedCookiesCountChanged(0));
cookie_controls()->Update(web_contents());
testing::Mock::VerifyAndClearExpectations(mock());
// Accessing cookies should not change anything.
EXPECT_CALL(*mock(), OnBlockedCookiesCountChanged(0));
tab_specific_content_settings()->OnWebDatabaseAccessed(
GURL("https://example.com"), /*blocked=*/false);
EXPECT_EQ(0, cookie_controls()->GetBlockedDomainCount());
testing::Mock::VerifyAndClearExpectations(mock());
// Blocking cookies should update the blocked cookie count.
EXPECT_CALL(*mock(), OnBlockedCookiesCountChanged(1));
tab_specific_content_settings()->OnWebDatabaseAccessed(
GURL("https://thirdparty.com"), /*blocked=*/true);
EXPECT_EQ(1, cookie_controls()->GetBlockedDomainCount());
testing::Mock::VerifyAndClearExpectations(mock());
// Navigating somewhere else should reset the cookie count.
NavigateAndCommit(GURL("https://somethingelse.com"));
EXPECT_CALL(*mock(),
OnStatusChanged(CookieControlsController::Status::kEnabled));
EXPECT_CALL(*mock(), OnBlockedCookiesCountChanged(0));
cookie_controls()->Update(web_contents());
}
TEST_F(CookieControlsTest, PreferenceDisabled) {
NavigateAndCommit(GURL("https://example.com"));
EXPECT_CALL(*mock(),
OnStatusChanged(CookieControlsController::Status::kEnabled));
EXPECT_CALL(*mock(), OnBlockedCookiesCountChanged(0));
cookie_controls()->Update(web_contents());
testing::Mock::VerifyAndClearExpectations(mock());
// Disabling the feature should disable the UI.
EXPECT_CALL(*mock(),
OnStatusChanged(CookieControlsController::Status::kDisabled));
EXPECT_CALL(*mock(), OnBlockedCookiesCountChanged(0));
profile()->GetPrefs()->SetInteger(
prefs::kCookieControlsMode,
static_cast<int>(content_settings::CookieControlsMode::kOff));
testing::Mock::VerifyAndClearExpectations(mock());
}
TEST_F(CookieControlsTest, DisableForSite) {
NavigateAndCommit(GURL("https://example.com"));
EXPECT_CALL(*mock(),
OnStatusChanged(CookieControlsController::Status::kEnabled));
EXPECT_CALL(*mock(), OnBlockedCookiesCountChanged(0));
cookie_controls()->Update(web_contents());
testing::Mock::VerifyAndClearExpectations(mock());
// Disabling cookie blocking for example.com should update the ui.
EXPECT_CALL(*mock(), OnStatusChanged(
CookieControlsController::Status::kDisabledForSite));
EXPECT_CALL(*mock(), OnBlockedCookiesCountChanged(0));
cookie_controls()->OnCookieBlockingEnabledForSite(false);
testing::Mock::VerifyAndClearExpectations(mock());
// Visiting some other site, should switch back to kEnabled.
NavigateAndCommit(GURL("https://somethingelse.com"));
EXPECT_CALL(*mock(),
OnStatusChanged(CookieControlsController::Status::kEnabled));
EXPECT_CALL(*mock(), OnBlockedCookiesCountChanged(0));
cookie_controls()->Update(web_contents());
testing::Mock::VerifyAndClearExpectations(mock());
// Visiting example.com should set status to kDisabledForSite.
NavigateAndCommit(GURL("https://example.com"));
EXPECT_CALL(*mock(), OnStatusChanged(
CookieControlsController::Status::kDisabledForSite));
EXPECT_CALL(*mock(), OnBlockedCookiesCountChanged(0));
cookie_controls()->Update(web_contents());
testing::Mock::VerifyAndClearExpectations(mock());
// Enabling example.com again should change status to kEnabled.
EXPECT_CALL(*mock(),
OnStatusChanged(CookieControlsController::Status::kEnabled));
EXPECT_CALL(*mock(), OnBlockedCookiesCountChanged(0));
cookie_controls()->OnCookieBlockingEnabledForSite(true);
testing::Mock::VerifyAndClearExpectations(mock());
}
// Copyright 2019 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef CHROME_BROWSER_UI_COOKIE_CONTROLS_COOKIE_CONTROLS_VIEW_H_
#define CHROME_BROWSER_UI_COOKIE_CONTROLS_COOKIE_CONTROLS_VIEW_H_
#include "base/observer_list_types.h"
#include "chrome/browser/ui/cookie_controls/cookie_controls_controller.h"
// Interface for the CookieControls UI.
class CookieControlsView : public base::CheckedObserver {
public:
virtual void OnStatusChanged(CookieControlsController::Status status) = 0;
virtual void OnBlockedCookiesCountChanged(int blocked_cookies) = 0;
};
#endif // CHROME_BROWSER_UI_COOKIE_CONTROLS_COOKIE_CONTROLS_VIEW_H_
......@@ -20,6 +20,7 @@ enum class PageActionIconType {
kZoom,
kNativeFileSystemAccess,
kClickToCall,
kCookieControls,
};
class PageActionIconContainer {
......
......@@ -21,6 +21,8 @@
#include "chrome/browser/ui/views/location_bar/content_setting_image_view.h"
#include "chrome/browser/ui/views/page_action/omnibox_page_action_icon_container_view.h"
#include "chrome/browser/ui/views/toolbar/browser_actions_container.h"
#include "components/content_settings/core/browser/cookie_settings.h"
#include "components/content_settings/core/common/features.h"
#include "third_party/blink/public/common/features.h"
#include "ui/base/hit_test.h"
#include "ui/compositor/layer_animation_element.h"
......@@ -222,6 +224,8 @@ HostedAppButtonContainer::HostedAppButtonContainer(
params.types_enabled.push_back(PageActionIconType::kZoom);
if (base::FeatureList::IsEnabled(blink::features::kNativeFileSystemAPI))
params.types_enabled.push_back(PageActionIconType::kNativeFileSystemAccess);
if (base::FeatureList::IsEnabled(content_settings::kImprovedCookieControls))
params.types_enabled.push_back(PageActionIconType::kCookieControls);
params.icon_size = GetLayoutConstant(HOSTED_APP_PAGE_ACTION_ICON_SIZE);
params.icon_color = GetCaptionColor();
params.between_icon_spacing = HorizontalPaddingBetweenItems();
......
// Copyright 2019 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "chrome/browser/ui/views/location_bar/cookie_controls_bubble_view.h"
#include <memory>
#include "base/logging.h"
#include "chrome/app/vector_icons/vector_icons.h"
#include "chrome/browser/ui/cookie_controls/cookie_controls_controller.h"
#include "chrome/browser/ui/views/chrome_layout_provider.h"
#include "chrome/grit/generated_resources.h"
#include "chrome/grit/theme_resources.h"
#include "ui/base/l10n/l10n_util.h"
#include "ui/base/resource/resource_bundle.h"
#include "ui/base/ui_base_types.h"
#include "ui/gfx/text_utils.h"
#include "ui/gfx/vector_icon_types.h"
#include "ui/views/controls/button/button.h"
#include "ui/views/controls/button/md_text_button.h"
#include "ui/views/controls/image_view.h"
#include "ui/views/controls/label.h"
#include "ui/views/layout/box_layout.h"
#include "ui/views/style/typography.h"
#include "ui/views/widget/widget.h"
CookieControlsBubbleView* CookieControlsBubbleView::cookie_bubble_ = nullptr;
// static
void CookieControlsBubbleView::ShowBubble(
views::View* anchor_view,
views::Button* highlighted_button,
content::WebContents* web_contents,
CookieControlsController* controller,
CookieControlsController::Status status) {
DCHECK(web_contents);
if (cookie_bubble_)
return;
cookie_bubble_ =
new CookieControlsBubbleView(anchor_view, web_contents, controller);
cookie_bubble_->SetHighlightedButton(highlighted_button);
views::Widget* bubble_widget =
views::BubbleDialogDelegateView::CreateBubble(cookie_bubble_);
controller->Update(web_contents);
bubble_widget->Show();
}
// static
CookieControlsBubbleView* CookieControlsBubbleView::GetCookieBubble() {
return cookie_bubble_;
}
void CookieControlsBubbleView::OnStatusChanged(
CookieControlsController::Status status) {
if (status_ == status)
return;
status_ = status;
UpdateUi(status, blocked_cookies_ > 0);
}
void CookieControlsBubbleView::OnBlockedCookiesCountChanged(
int blocked_cookies) {
// The blocked cookie count changes quite frequently, so avoid unnecessary
// UI updates and unnecessarily calling GetBlockedDomainCount() if possible.
if (blocked_cookies_ == blocked_cookies)
return;
bool has_blocked_changed = (blocked_cookies_ > 0) != (blocked_cookies > 0);
blocked_cookies_ = blocked_cookies;
sub_title_->SetText(
l10n_util::GetPluralStringFUTF16(IDS_COOKIE_CONTROLS_BLOCKED_MESSAGE,
controller_->GetBlockedDomainCount()));
// If this only incremented the number of blocked sites, no UI update is
// necessary besides the |sub_title_| text.
if (has_blocked_changed)
UpdateUi(status_, blocked_cookies_ > 0);
}
CookieControlsBubbleView::CookieControlsBubbleView(
views::View* anchor_view,
content::WebContents* web_contents,
CookieControlsController* controller)
: LocationBarBubbleDelegateView(anchor_view, web_contents),
controller_(controller) {
observer_.Add(controller);
}
CookieControlsBubbleView::~CookieControlsBubbleView() = default;
void CookieControlsBubbleView::UpdateUi(CookieControlsController::Status status,
bool has_blocked_cookies) {
if (status == CookieControlsController::Status::kDisabled) {
CloseBubble();
return;
}
if (status == CookieControlsController::Status::kEnabled) {
header_image_->SetImage(
ui::ResourceBundle::GetSharedInstance().GetImageSkiaNamed(
has_blocked_cookies ? IDR_COOKIE_BLOCKING_ON_HEADER
: IDR_COOKIE_BLOCKING_INACTIVE_HEADER));
title_->SetText(
l10n_util::GetStringUTF16(IDS_COOKIE_CONTROLS_DIALOG_TITLE));
sub_title_->SetVisible(true);
spacer_->SetVisible(has_blocked_cookies);
turn_off_button_->SetVisible(has_blocked_cookies);
turn_on_button_->SetVisible(false);
} else {
DCHECK_EQ(status, CookieControlsController::Status::kDisabledForSite);
header_image_->SetImage(
ui::ResourceBundle::GetSharedInstance().GetImageSkiaNamed(
IDR_COOKIE_BLOCKING_OFF_HEADER));
title_->SetText(
l10n_util::GetStringUTF16(IDS_COOKIE_CONTROLS_DIALOG_TITLE_OFF));
sub_title_->SetVisible(false);
spacer_->SetVisible(true);
turn_off_button_->SetVisible(false);
turn_on_button_->SetVisible(true);
}
Layout();
SizeToContents();
}
void CookieControlsBubbleView::CloseBubble() {
// Widget's Close() is async, but we don't want to use cookie_bubble_ after
// this. Additionally web_contents() may have been destroyed.
cookie_bubble_ = nullptr;
LocationBarBubbleDelegateView::CloseBubble();
}
int CookieControlsBubbleView::GetDialogButtons() const {
return ui::DIALOG_BUTTON_NONE;
}
void CookieControlsBubbleView::Init() {
SetLayoutManager(std::make_unique<views::BoxLayout>(
views::BoxLayout::Orientation::kVertical));
header_image_ = new views::ImageView();
AddChildView(header_image_);
title_ =
new views::Label(base::string16(), views::style::CONTEXT_DIALOG_TITLE);
title_->SetBorder(views::CreateEmptyBorder(8, 0, 0, 0));
title_->SetHorizontalAlignment(gfx::HorizontalAlignment::ALIGN_LEFT);
title_->SetMultiLine(true);
AddChildView(title_);
sub_title_ = new views::Label(base::string16(), views::style::CONTEXT_LABEL);
sub_title_->SetBorder(views::CreateEmptyBorder(8, 0, 0, 0));
sub_title_->SetHorizontalAlignment(gfx::HorizontalAlignment::ALIGN_LEFT);
AddChildView(sub_title_);
spacer_ = new views::View();
spacer_->SetPreferredSize(gfx::Size(0, 16));
AddChildView(spacer_);
auto* button_container = new views::View();
button_container->SetLayoutManager(std::make_unique<views::BoxLayout>(
views::BoxLayout::Orientation::kHorizontal));
turn_on_button_ =
views::MdTextButton::CreateSecondaryUiButton(
this, l10n_util::GetStringUTF16(IDS_COOKIE_CONTROLS_TURN_ON_BUTTON))
.release();
button_container->AddChildView(turn_on_button_);
turn_off_button_ =
views::MdTextButton::CreateSecondaryUiButton(
this, l10n_util::GetStringUTF16(IDS_COOKIE_CONTROLS_TURN_OFF_BUTTON))
.release();
button_container->AddChildView(turn_off_button_);
AddChildView(button_container);
}
bool CookieControlsBubbleView::ShouldShowWindowTitle() const {
return false;
}
bool CookieControlsBubbleView::ShouldShowCloseButton() const {
return true;
}
void CookieControlsBubbleView::WindowClosing() {
// |cookie_bubble_| can be a new bubble by this point (as Close(); doesn't
// call this right away). Only set to nullptr when it's this bubble.
bool this_bubble = cookie_bubble_ == this;
if (this_bubble)
cookie_bubble_ = nullptr;
controller_->OnBubbleUiClosing(web_contents());
}
void CookieControlsBubbleView::ButtonPressed(views::Button* sender,
const ui::Event& event) {
if (sender == turn_off_button_) {
controller_->OnCookieBlockingEnabledForSite(false);
} else {
DCHECK_EQ(sender, turn_on_button_);
controller_->OnCookieBlockingEnabledForSite(true);
}
}
// Copyright 2019 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef CHROME_BROWSER_UI_VIEWS_LOCATION_BAR_COOKIE_CONTROLS_BUBBLE_VIEW_H_
#define CHROME_BROWSER_UI_VIEWS_LOCATION_BAR_COOKIE_CONTROLS_BUBBLE_VIEW_H_
#include "base/macros.h"
#include "chrome/browser/ui/cookie_controls/cookie_controls_view.h"
#include "chrome/browser/ui/views/location_bar/location_bar_bubble_delegate_view.h"
#include "components/content_settings/core/browser/cookie_settings.h"
#include "ui/views/controls/button/button.h"
class CookieControlsController;
namespace content {
class WebContents;
}
namespace views {
class ImageView;
class Label;
} // namespace views
// View used to display the cookie controls ui.
class CookieControlsBubbleView : public LocationBarBubbleDelegateView,
public views::ButtonListener,
public CookieControlsView {
public:
static void ShowBubble(views::View* anchor_view,
views::Button* highlighted_button,
content::WebContents* web_contents,
CookieControlsController* controller,
CookieControlsController::Status status);
static CookieControlsBubbleView* GetCookieBubble();
// CookieControlsView:
void OnStatusChanged(CookieControlsController::Status status) override;
void OnBlockedCookiesCountChanged(int blocked_cookies) override;
private:
CookieControlsBubbleView(views::View* anchor_view,
content::WebContents* web_contents,
CookieControlsController* cookie_contols);
~CookieControlsBubbleView() override;
void UpdateUi(CookieControlsController::Status status,
bool has_blocked_cookies);
// LocationBarBubbleDelegateView:
void CloseBubble() override;
int GetDialogButtons() const override;
void Init() override;
bool ShouldShowWindowTitle() const override;
bool ShouldShowCloseButton() const override;
void WindowClosing() override;
// views::ButtonListener:
void ButtonPressed(views::Button* sender, const ui::Event& event) override;
// Singleton instance of the cookie bubble. The cookie bubble can only be
// shown on the active browser window, so there is no case in which it will be
// shown twice at the same time.
static CookieControlsBubbleView* cookie_bubble_;
CookieControlsController* controller_ = nullptr;
CookieControlsController::Status status_ =
CookieControlsController::Status::kUninitialized;
int blocked_cookies_ = -1;
views::ImageView* header_image_ = nullptr;
views::Button* turn_on_button_ = nullptr;
views::Button* turn_off_button_ = nullptr;
views::Label* title_ = nullptr;
views::Label* sub_title_ = nullptr;
views::View* spacer_ = nullptr;
ScopedObserver<CookieControlsController, CookieControlsView> observer_{this};
DISALLOW_COPY_AND_ASSIGN(CookieControlsBubbleView);
};
#endif // CHROME_BROWSER_UI_VIEWS_LOCATION_BAR_COOKIE_CONTROLS_BUBBLE_VIEW_H_
// Copyright 2019 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "chrome/browser/ui/views/location_bar/cookie_controls_icon_view.h"
#include <memory>
#include "base/logging.h"
#include "base/strings/utf_string_conversions.h"
#include "chrome/app/vector_icons/vector_icons.h"
#include "chrome/browser/ui/cookie_controls/cookie_controls_controller.h"
#include "chrome/browser/ui/view_ids.h"
#include "chrome/browser/ui/views/location_bar/cookie_controls_bubble_view.h"
#include "chrome/grit/generated_resources.h"
#include "ui/base/l10n/l10n_util.h"
#include "ui/gfx/geometry/size.h"
#include "ui/gfx/paint_vector_icon.h"
CookieControlsIconView::CookieControlsIconView(
PageActionIconView::Delegate* delegate)
: PageActionIconView(nullptr, 0, delegate) {
SetVisible(false);
}
CookieControlsIconView::~CookieControlsIconView() = default;
bool CookieControlsIconView::Update() {
bool was_visible = GetVisible();
auto* web_contents = delegate()->GetWebContentsForPageActionIconView();
if (web_contents) {
if (!controller_) {
controller_ = std::make_unique<CookieControlsController>(web_contents);
observer_.Add(controller_.get());
}
controller_->Update(web_contents);
}
SetVisible(ShouldBeVisible());
return GetVisible() != was_visible;
}
void CookieControlsIconView::OnStatusChanged(
CookieControlsController::Status status) {
if (status_ != status) {
status_ = status;
SetVisible(ShouldBeVisible());
UpdateIconImage();
}
}
void CookieControlsIconView::OnBlockedCookiesCountChanged(int blocked_cookies) {
// The blocked cookie count changes quite frequently, so avoid unnecessary
// UI updates.
if (has_blocked_cookies_ != blocked_cookies > 0) {
has_blocked_cookies_ = blocked_cookies > 0;
UpdateIconImage();
}
}
bool CookieControlsIconView::ShouldBeVisible() const {
if (delegate()->IsLocationBarUserInputInProgress())
return false;
if (HasAssociatedBubble())
return true;
if (!delegate()->GetWebContentsForPageActionIconView())
return false;
return status_ != CookieControlsController::Status::kDisabled;
}
bool CookieControlsIconView::HasAssociatedBubble() const {
if (!GetBubble())
return false;
// There may be multiple icons but only a single bubble can be displayed
// at a time. Check if the bubble belongs to this icon.
if (!GetBubble()->GetAnchorView())
return false;
return GetBubble()->GetAnchorView()->GetWidget() == GetWidget();
}
void CookieControlsIconView::OnExecuting(
PageActionIconView::ExecuteSource source) {
CookieControlsBubbleView::ShowBubble(
this, this, delegate()->GetWebContentsForPageActionIconView(),
controller_.get(), status_);
}
views::BubbleDialogDelegateView* CookieControlsIconView::GetBubble() const {
return CookieControlsBubbleView::GetCookieBubble();
}
const gfx::VectorIcon& CookieControlsIconView::GetVectorIcon() const {
if (status_ == CookieControlsController::Status::kDisabledForSite)
return kShieldOffIcon;
return kShieldOutlineIcon;
}
const gfx::VectorIcon& CookieControlsIconView::GetVectorIconBadge() const {
if (status_ == CookieControlsController::Status::kEnabled &&
has_blocked_cookies_)
return kBlockedBadgeIcon;
return gfx::kNoneIcon;
}
base::string16 CookieControlsIconView::GetTextForTooltipAndAccessibleName()
const {
return l10n_util::GetStringUTF16(IDS_COOKIE_CONTROLS_TOOLTIP);
}
// Copyright 2019 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef CHROME_BROWSER_UI_VIEWS_LOCATION_BAR_COOKIE_CONTROLS_ICON_VIEW_H_
#define CHROME_BROWSER_UI_VIEWS_LOCATION_BAR_COOKIE_CONTROLS_ICON_VIEW_H_
#include <memory>
#include "base/macros.h"
#include "base/scoped_observer.h"
#include "chrome/browser/ui/cookie_controls/cookie_controls_controller.h"
#include "chrome/browser/ui/cookie_controls/cookie_controls_view.h"
#include "chrome/browser/ui/views/location_bar/cookie_controls_bubble_view.h"
#include "chrome/browser/ui/views/page_action/page_action_icon_view.h"
// View for the cookie control icon in the Omnibox.
class CookieControlsIconView : public PageActionIconView,
public CookieControlsView {
public:
explicit CookieControlsIconView(PageActionIconView::Delegate* delegate);
~CookieControlsIconView() override;
// CookieControlsUI:
void OnStatusChanged(CookieControlsController::Status status) override;
void OnBlockedCookiesCountChanged(int blocked_cookies) override;
// PageActionIconView:
views::BubbleDialogDelegateView* GetBubble() const override;
bool Update() override;
base::string16 GetTextForTooltipAndAccessibleName() const override;
protected:
void OnExecuting(PageActionIconView::ExecuteSource source) override;
const gfx::VectorIcon& GetVectorIcon() const override;
const gfx::VectorIcon& GetVectorIconBadge() const override;
private:
bool HasAssociatedBubble() const;
bool ShouldBeVisible() const;
CookieControlsController::Status status_ =
CookieControlsController::Status::kUninitialized;
bool has_blocked_cookies_ = false;
std::unique_ptr<CookieControlsController> controller_;
ScopedObserver<CookieControlsController, CookieControlsView> observer_{this};
DISALLOW_COPY_AND_ASSIGN(CookieControlsIconView);
};
#endif // CHROME_BROWSER_UI_VIEWS_LOCATION_BAR_COOKIE_CONTROLS_ICON_VIEW_H_
......@@ -66,6 +66,7 @@
#include "chrome/grit/generated_resources.h"
#include "components/autofill/core/common/autofill_payments_features.h"
#include "components/bookmarks/common/bookmark_pref_names.h"
#include "components/content_settings/core/common/features.h"
#include "components/dom_distiller/core/dom_distiller_switches.h"
#include "components/favicon/content/content_favicon_driver.h"
#include "components/omnibox/browser/location_bar_model.h"
......@@ -252,6 +253,11 @@ void LocationBarView::Init() {
browser_->is_type_normal()) {
params.types_enabled.push_back(PageActionIconType::kReaderMode);
}
if (base::FeatureList::IsEnabled(
content_settings::kImprovedCookieControls)) {
params.types_enabled.push_back(PageActionIconType::kCookieControls);
}
}
params.icon_size = GetLayoutConstant(LOCATION_BAR_ICON_SIZE);
params.icon_color = icon_color;
......
......@@ -6,6 +6,7 @@
#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/ui/browser.h"
#include "chrome/browser/ui/views/location_bar/cookie_controls_icon_view.h"
#include "chrome/browser/ui/views/location_bar/find_bar_icon.h"
#include "chrome/browser/ui/views/location_bar/intent_picker_view.h"
#include "chrome/browser/ui/views/location_bar/zoom_bubble_view.h"
......@@ -76,6 +77,11 @@ OmniboxPageActionIconContainerView::OmniboxPageActionIconContainerView(
zoom_view_ = new ZoomView(params.page_action_icon_delegate);
page_action_icons_.push_back(zoom_view_);
break;
case PageActionIconType::kCookieControls:
cookie_view_ =
new CookieControlsIconView(params.page_action_icon_delegate);
page_action_icons_.push_back(cookie_view_);
break;
case PageActionIconType::kSendTabToSelf:
send_tab_to_self_icon_view_ =
new send_tab_to_self::SendTabToSelfIconView(
......@@ -134,6 +140,8 @@ PageActionIconView* OmniboxPageActionIconContainerView::GetPageActionIconView(
return translate_icon_;
case PageActionIconType::kZoom:
return zoom_view_;
case PageActionIconType::kCookieControls:
return cookie_view_;
case PageActionIconType::kSendTabToSelf:
return send_tab_to_self_icon_view_;
case PageActionIconType::kNativeFileSystemAccess:
......
......@@ -18,6 +18,7 @@
class Browser;
class ClickToCallIconView;
class CommandUpdater;
class CookieControlsIconView;
class FindBarIcon;
class IntentPickerView;
class ManagePasswordsIconViews;
......@@ -88,6 +89,7 @@ class OmniboxPageActionIconContainerView
ManagePasswordsIconViews* manage_passwords_icon_ = nullptr;
IntentPickerView* intent_picker_view_ = nullptr;
PwaInstallView* pwa_install_view_ = nullptr;
CookieControlsIconView* cookie_view_ = nullptr;
send_tab_to_self::SendTabToSelfIconView* send_tab_to_self_icon_view_ =
nullptr;
TranslateIconView* translate_icon_ = nullptr;
......
......@@ -3761,6 +3761,7 @@ test("unit_tests") {
"../browser/ui/chrome_bubble_manager_unittest.cc",
"../browser/ui/content_settings/content_setting_bubble_model_unittest.cc",
"../browser/ui/content_settings/content_setting_image_model_unittest.cc",
"../browser/ui/cookie_controls/cookie_controls_controller_unittest.cc",
"../browser/ui/exclusive_access/fullscreen_controller_state_unittest.cc",
"../browser/ui/extensions/extension_action_view_controller_unittest.cc",
"../browser/ui/extensions/extension_message_bubble_bridge_unittest.cc",
......
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