blob: ef3d5d093e0254467c3f5d7e5210130b7207ea90 [file] [log] [blame]
// Copyright 2012 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "chrome/browser/ui/content_settings/content_setting_image_model.h"
#include <algorithm>
#include <string>
#include <utility>
#include "base/feature_list.h"
#include "base/metrics/field_trial_params.h"
#include "base/metrics/user_metrics.h"
#include "base/metrics/user_metrics_action.h"
#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/page_specific_content_settings_delegate.h"
#include "chrome/browser/download/download_request_limiter.h"
#include "chrome/browser/permissions/quiet_notification_permission_ui_config.h"
#include "chrome/browser/permissions/quiet_notification_permission_ui_state.h"
#include "chrome/browser/permissions/system/system_permission_settings.h"
#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/ui/blocked_content/framebust_block_tab_helper.h"
#include "chrome/browser/ui/browser.h"
#include "chrome/browser/ui/browser_finder.h"
#include "chrome/browser/ui/content_settings/content_setting_bubble_model.h"
#include "chrome/browser/ui/content_settings/content_setting_image_model_states.h"
#include "chrome/browser/ui/layout_constants.h"
#include "chrome/browser/ui/ui_features.h"
#include "chrome/browser/ui/web_applications/app_browser_controller.h"
#include "chrome/common/chrome_features.h"
#include "chrome/common/pref_names.h"
#include "chrome/grit/branded_strings.h"
#include "chrome/grit/generated_resources.h"
#include "components/content_settings/browser/page_specific_content_settings.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/no_state_prefetch/browser/no_state_prefetch_manager.h"
#include "components/permissions/features.h"
#include "components/permissions/permission_request_manager.h"
#include "components/prefs/pref_service.h"
#include "components/strings/grit/components_strings.h"
#include "components/vector_icons/vector_icons.h"
#include "content/public/browser/web_contents.h"
#include "media/base/media_switches.h"
#include "net/base/schemeful_site.h"
#include "services/device/public/cpp/device_features.h"
#include "ui/base/l10n/l10n_util.h"
#include "ui/base/pointer/touch_ui_controller.h"
#include "ui/base/ui_base_features.h"
#include "ui/gfx/color_palette.h"
#include "ui/gfx/color_utils.h"
#include "ui/gfx/favicon_size.h"
#include "ui/gfx/image/image_skia.h"
#include "ui/gfx/paint_vector_icon.h"
#include "ui/gfx/vector_icon_types.h"
#if BUILDFLAG(IS_MAC)
#include "chrome/browser/browser_process_platform_part.h"
#include "chrome/browser/permissions/system/system_media_capture_permissions_mac.h"
#include "chrome/browser/web_applications/os_integration/mac/app_shim_registry.h"
#include "chrome/browser/web_applications/web_app_tab_helper.h"
#endif
using content::WebContents;
using content_settings::PageSpecificContentSettings;
// The image models hierarchy:
//
// ContentSettingImageModel - base class
// ContentSettingSimpleImageModel - single content setting
// ContentSettingBlockedImageModel - generic blocked setting
// ContentSettingGeolocationImageModel - geolocation
// ContentSettingRPHImageModel - protocol handlers
// ContentSettingMIDISysExImageModel - midi sysex
// ContentSettingDownloadsImageModel - automatic downloads
// ContentSettingClipboardReadWriteImageModel - clipboard read and write
// ContentSettingSensorsImageModel - sensors
// ContentSettingNotificationsImageModel - notifications
// ContentSettingMediaImageModel - media
// ContentSettingFramebustBlockImageModel - blocked framebust
constexpr bool kNotifyAccessibility = true;
class ContentSettingBlockedImageModel : public ContentSettingSimpleImageModel {
public:
ContentSettingBlockedImageModel(ImageType image_type,
ContentSettingsType content_type);
ContentSettingBlockedImageModel(const ContentSettingBlockedImageModel&) =
delete;
ContentSettingBlockedImageModel& operator=(
const ContentSettingBlockedImageModel&) = delete;
bool UpdateAndGetVisibility(WebContents* web_contents) override;
};
class ContentSettingGeolocationImageModel : public ContentSettingImageModel {
public:
ContentSettingGeolocationImageModel();
ContentSettingGeolocationImageModel(
const ContentSettingGeolocationImageModel&) = delete;
ContentSettingGeolocationImageModel& operator=(
const ContentSettingGeolocationImageModel&) = delete;
~ContentSettingGeolocationImageModel() override;
bool UpdateAndGetVisibility(WebContents* web_contents) override;
bool IsGeolocationAccessed();
std::unique_ptr<ContentSettingBubbleModel> CreateBubbleModelImpl(
ContentSettingBubbleModel::Delegate* delegate,
WebContents* web_contents) override;
};
class ContentSettingRPHImageModel : public ContentSettingSimpleImageModel {
public:
ContentSettingRPHImageModel();
ContentSettingRPHImageModel(const ContentSettingRPHImageModel&) = delete;
ContentSettingRPHImageModel& operator=(const ContentSettingRPHImageModel&) =
delete;
bool UpdateAndGetVisibility(WebContents* web_contents) override;
};
class ContentSettingMIDISysExImageModel
: public ContentSettingSimpleImageModel {
public:
ContentSettingMIDISysExImageModel();
ContentSettingMIDISysExImageModel(const ContentSettingMIDISysExImageModel&) =
delete;
ContentSettingMIDISysExImageModel& operator=(
const ContentSettingMIDISysExImageModel&) = delete;
bool UpdateAndGetVisibility(WebContents* web_contents) override;
};
class ContentSettingDownloadsImageModel
: public ContentSettingSimpleImageModel {
public:
ContentSettingDownloadsImageModel();
ContentSettingDownloadsImageModel(const ContentSettingDownloadsImageModel&) =
delete;
ContentSettingDownloadsImageModel& operator=(
const ContentSettingDownloadsImageModel&) = delete;
bool UpdateAndGetVisibility(WebContents* web_contents) override;
};
class ContentSettingClipboardReadWriteImageModel
: public ContentSettingSimpleImageModel {
public:
ContentSettingClipboardReadWriteImageModel();
ContentSettingClipboardReadWriteImageModel(
const ContentSettingClipboardReadWriteImageModel&) = delete;
ContentSettingClipboardReadWriteImageModel& operator=(
const ContentSettingClipboardReadWriteImageModel&) = delete;
bool UpdateAndGetVisibility(WebContents* web_contents) override;
};
// Image model for displaying media icons in the location bar.
class ContentSettingMediaImageModel : public ContentSettingImageModel {
public:
ContentSettingMediaImageModel();
ContentSettingMediaImageModel(const ContentSettingMediaImageModel&) = delete;
ContentSettingMediaImageModel& operator=(
const ContentSettingMediaImageModel&) = delete;
bool UpdateAndGetVisibility(WebContents* web_contents) override;
bool IsMicAccessed();
bool IsCamAccessed();
bool IsMicBlockedOnSiteLevel();
bool IsCameraBlockedOnSiteLevel();
#if BUILDFLAG(IS_MAC)
bool DidCameraAccessFailBecauseOfSystemLevelBlock();
bool DidMicAccessFailBecauseOfSystemLevelBlock();
bool IsCameraAccessPendingOnSystemLevelPrompt();
bool IsMicAccessPendingOnSystemLevelPrompt();
#endif // BUILDFLAG(IS_MAC)
std::unique_ptr<ContentSettingBubbleModel> CreateBubbleModelImpl(
ContentSettingBubbleModel::Delegate* delegate,
WebContents* web_contents) override;
private:
PageSpecificContentSettings::MicrophoneCameraState state_;
};
#if BUILDFLAG(IS_CHROMEOS)
// Image model for displaying media icons in the location bar.
class ContentSettingSmartCardImageModel
: public ContentSettingSimpleImageModel {
public:
ContentSettingSmartCardImageModel()
: ContentSettingSimpleImageModel(ImageType::SMART_CARD,
ContentSettingsType::SMART_CARD_GUARD) {}
ContentSettingSmartCardImageModel(const ContentSettingSmartCardImageModel&) =
delete;
ContentSettingSmartCardImageModel& operator=(
const ContentSettingSmartCardImageModel&) = delete;
bool UpdateAndGetVisibility(WebContents* web_contents) override {
PageSpecificContentSettings* content_settings =
PageSpecificContentSettings::GetForFrame(
web_contents->GetPrimaryMainFrame());
if (!content_settings) {
return false;
}
// This should never appear when the permission is blocked.
SetIcon(ContentSettingsType::SMART_CARD_GUARD, /*blocked=*/false);
set_tooltip(l10n_util::GetStringUTF16(IDS_ACCESSED_SMART_CARD_READER_BODY));
return content_settings->ShouldShowDeviceInUseIndicator(
ContentSettingsType::SMART_CARD_GUARD);
}
std::unique_ptr<ContentSettingBubbleModel> CreateBubbleModelImpl(
ContentSettingBubbleModel::Delegate* delegate,
WebContents* web_contents) override {
return std::make_unique<ContentSettingSimpleBubbleModel>(
delegate, web_contents, ContentSettingsType::SMART_CARD_GUARD);
}
};
#endif // BUILDFLAG(IS_CHROMEOS)
class ContentSettingSensorsImageModel : public ContentSettingSimpleImageModel {
public:
ContentSettingSensorsImageModel();
ContentSettingSensorsImageModel(const ContentSettingSensorsImageModel&) =
delete;
ContentSettingSensorsImageModel& operator=(
const ContentSettingSensorsImageModel&) = delete;
bool UpdateAndGetVisibility(WebContents* web_contents) override;
};
// The image model for an icon that acts as a quiet permission request prompt
// for notifications. In contrast to other icons -- which are either
// permission-in-use indicators or permission-blocked indicators -- this is
// shown before the user makes the first permission decision, and in fact,
// allows the user to make that decision.
class ContentSettingNotificationsImageModel
: public ContentSettingSimpleImageModel {
public:
ContentSettingNotificationsImageModel();
ContentSettingNotificationsImageModel(
const ContentSettingNotificationsImageModel&) = delete;
ContentSettingNotificationsImageModel& operator=(
const ContentSettingNotificationsImageModel&) = delete;
// ContentSettingSimpleImageModel:
bool UpdateAndGetVisibility(WebContents* web_contents) override;
std::unique_ptr<ContentSettingBubbleModel> CreateBubbleModelImpl(
ContentSettingBubbleModel::Delegate* delegate,
WebContents* web_contents) override;
};
class ContentSettingPopupImageModel : public ContentSettingSimpleImageModel {
public:
ContentSettingPopupImageModel();
ContentSettingPopupImageModel(const ContentSettingPopupImageModel&) = delete;
ContentSettingPopupImageModel& operator=(
const ContentSettingPopupImageModel&) = delete;
bool UpdateAndGetVisibility(WebContents* web_contents) override;
};
class ContentSettingStorageAccessImageModel
: public ContentSettingSimpleImageModel {
public:
ContentSettingStorageAccessImageModel();
ContentSettingStorageAccessImageModel(
const ContentSettingStorageAccessImageModel&) = delete;
ContentSettingStorageAccessImageModel& operator=(
const ContentSettingStorageAccessImageModel&) = delete;
bool UpdateAndGetVisibility(WebContents* web_contents) override;
};
#if BUILDFLAG(IS_WIN)
class ContentSettingProtectedMediaIdentifierImageModel
: public ContentSettingSimpleImageModel {
public:
ContentSettingProtectedMediaIdentifierImageModel();
ContentSettingProtectedMediaIdentifierImageModel(
const ContentSettingProtectedMediaIdentifierImageModel&) = delete;
ContentSettingProtectedMediaIdentifierImageModel& operator=(
const ContentSettingProtectedMediaIdentifierImageModel&) = delete;
bool UpdateAndGetVisibility(WebContents* web_contents) override;
};
#endif // BUILDFLAG(IS_WIN)
namespace {
struct ContentSettingsImageDetails {
ContentSettingsType content_type;
int blocked_tooltip_id;
int blocked_explanatory_text_id;
int accessed_tooltip_id;
};
constexpr ContentSettingsImageDetails kImageDetails[] = {
{ContentSettingsType::COOKIES, IDS_BLOCKED_ON_DEVICE_SITE_DATA_MESSAGE, 0,
IDS_ACCESSED_ON_DEVICE_SITE_DATA_MESSAGE},
{ContentSettingsType::IMAGES, IDS_BLOCKED_IMAGES_MESSAGE, 0, 0},
{ContentSettingsType::JAVASCRIPT, IDS_BLOCKED_JAVASCRIPT_MESSAGE, 0, 0},
{ContentSettingsType::MIXEDSCRIPT, IDS_BLOCKED_DISPLAYING_INSECURE_CONTENT,
0, 0},
{ContentSettingsType::SOUND, IDS_BLOCKED_SOUND_TITLE, 0, 0},
{ContentSettingsType::ADS, IDS_BLOCKED_ADS_PROMPT_TOOLTIP,
IDS_BLOCKED_ADS_PROMPT_TITLE, 0},
};
const ContentSettingsImageDetails* GetImageDetails(ContentSettingsType type) {
for (const ContentSettingsImageDetails& image_details : kImageDetails) {
if (image_details.content_type == type) {
return &image_details;
}
}
return nullptr;
}
void GetIconChromeRefresh(ContentSettingsType type,
bool blocked,
raw_ptr<const gfx::VectorIcon>* icon) {
switch (type) {
case ContentSettingsType::COOKIES:
*icon = blocked ? &vector_icons::kDatabaseOffIcon
: &vector_icons::kDatabaseIcon;
return;
case ContentSettingsType::IMAGES:
*icon = blocked ? &vector_icons::kPhotoOffChromeRefreshIcon
: &vector_icons::kPhotoChromeRefreshIcon;
return;
case ContentSettingsType::JAVASCRIPT:
*icon = blocked ? &vector_icons::kCodeOffChromeRefreshIcon
: &vector_icons::kCodeChromeRefreshIcon;
return;
case ContentSettingsType::MIXEDSCRIPT:
*icon = blocked ? &vector_icons::kNotSecureWarningOffChromeRefreshIcon
: &vector_icons::kNotSecureWarningChromeRefreshIcon;
return;
case ContentSettingsType::SOUND:
*icon = blocked ? &vector_icons::kVolumeOffChromeRefreshIcon
: &vector_icons::kVolumeUpChromeRefreshIcon;
return;
case ContentSettingsType::ADS:
*icon = blocked ? &vector_icons::kAdsOffChromeRefreshIcon
: &vector_icons::kAdsChromeRefreshIcon;
return;
case ContentSettingsType::GEOLOCATION:
*icon = blocked ? &vector_icons::kLocationOffChromeRefreshIcon
: &vector_icons::kLocationOnChromeRefreshIcon;
return;
case ContentSettingsType::PROTOCOL_HANDLERS:
*icon = blocked ? &vector_icons::kProtocolHandlerOffChromeRefreshIcon
: &vector_icons::kProtocolHandlerChromeRefreshIcon;
return;
case ContentSettingsType::MIDI_SYSEX:
*icon = blocked ? &vector_icons::kMidiOffChromeRefreshIcon
: &vector_icons::kMidiChromeRefreshIcon;
return;
case ContentSettingsType::AUTOMATIC_DOWNLOADS:
*icon = blocked ? &vector_icons::kFileDownloadOffChromeRefreshIcon
: &vector_icons::kFileDownloadChromeRefreshIcon;
return;
case ContentSettingsType::CLIPBOARD_READ_WRITE:
*icon = blocked ? &vector_icons::kContentPasteOffIcon
: &vector_icons::kContentPasteIcon;
return;
case ContentSettingsType::MEDIASTREAM_MIC:
*icon = blocked ? &vector_icons::kMicOffChromeRefreshIcon
: &vector_icons::kMicChromeRefreshIcon;
return;
case ContentSettingsType::MEDIASTREAM_CAMERA:
*icon = blocked ? &vector_icons::kVideocamOffChromeRefreshIcon
: &vector_icons::kVideocamChromeRefreshIcon;
return;
case ContentSettingsType::NOTIFICATIONS:
*icon = blocked ? &vector_icons::kNotificationsOffChromeRefreshIcon
: &vector_icons::kNotificationsChromeRefreshIcon;
return;
case ContentSettingsType::SENSORS:
*icon = blocked ? &vector_icons::kSensorsOffChromeRefreshIcon
: &vector_icons::kSensorsChromeRefreshIcon;
return;
case ContentSettingsType::STORAGE_ACCESS:
*icon = blocked ? &vector_icons::kStorageAccessOffIcon
: &vector_icons::kStorageAccessIcon;
return;
case ContentSettingsType::POPUPS:
*icon =
blocked ? &vector_icons::kIframeOffIcon : &vector_icons::kIframeIcon;
return;
#if BUILDFLAG(IS_CHROMEOS)
case ContentSettingsType::SMART_CARD_GUARD:
// Indicator shows only when at least one connection is active, hence no
// need for the off icon.
*icon = &vector_icons::kSmartCardReaderIcon;
return;
#endif
#if BUILDFLAG(IS_WIN)
case ContentSettingsType::PROTECTED_MEDIA_IDENTIFIER:
*icon = blocked ? &vector_icons::kSyncSavedLocallyOffIcon
: &vector_icons::kSyncSavedLocallyIcon;
return;
#endif // BUILDFLAG(IS_WIN)
default:
NOTREACHED();
}
}
// A wrapper function that allows returning both post-chrome-refresh and
// pre-chrome-refresh icons. To minimize code churn, this method returns two
// icons: a base icon and a badge. The badge is painted on top of the base icon,
// which is only needed for pre-chrome-refresh disabled icons.
// |icon| and |badge| are output parameters.
void GetIconFromType(ContentSettingsType type,
bool blocked,
raw_ptr<const gfx::VectorIcon>* icon,
raw_ptr<const gfx::VectorIcon>* badge) {
*badge = &gfx::VectorIcon::EmptyIcon();
GetIconChromeRefresh(type, blocked, icon);
}
} // namespace
// Single content setting ------------------------------------------------------
ContentSettingSimpleImageModel::ContentSettingSimpleImageModel(
ImageType image_type,
ContentSettingsType content_type,
bool image_type_should_notify_accessibility)
: ContentSettingImageModel(image_type,
image_type_should_notify_accessibility),
content_type_(content_type) {}
std::unique_ptr<ContentSettingBubbleModel>
ContentSettingSimpleImageModel::CreateBubbleModelImpl(
ContentSettingBubbleModel::Delegate* delegate,
WebContents* web_contents) {
return ContentSettingBubbleModel::CreateContentSettingBubbleModel(
delegate, web_contents, content_type());
}
// static
std::unique_ptr<ContentSettingImageModel>
ContentSettingImageModel::CreateForContentType(ImageType image_type) {
switch (image_type) {
case ImageType::COOKIES:
return std::make_unique<ContentSettingBlockedImageModel>(
ImageType::COOKIES, ContentSettingsType::COOKIES);
case ImageType::IMAGES:
return std::make_unique<ContentSettingBlockedImageModel>(
ImageType::IMAGES, ContentSettingsType::IMAGES);
case ImageType::JAVASCRIPT:
return std::make_unique<ContentSettingBlockedImageModel>(
ImageType::JAVASCRIPT, ContentSettingsType::JAVASCRIPT);
case ImageType::POPUPS:
return std::make_unique<ContentSettingPopupImageModel>();
case ImageType::GEOLOCATION:
return std::make_unique<ContentSettingGeolocationImageModel>();
case ImageType::MIXEDSCRIPT:
return std::make_unique<ContentSettingBlockedImageModel>(
ImageType::MIXEDSCRIPT, ContentSettingsType::MIXEDSCRIPT);
case ImageType::PROTOCOL_HANDLERS:
return std::make_unique<ContentSettingRPHImageModel>();
case ImageType::MEDIASTREAM:
return std::make_unique<ContentSettingMediaImageModel>();
case ImageType::ADS:
return std::make_unique<ContentSettingBlockedImageModel>(
ImageType::ADS, ContentSettingsType::ADS);
case ImageType::AUTOMATIC_DOWNLOADS:
return std::make_unique<ContentSettingDownloadsImageModel>();
case ImageType::MIDI_SYSEX:
return std::make_unique<ContentSettingMIDISysExImageModel>();
case ImageType::SOUND:
return std::make_unique<ContentSettingBlockedImageModel>(
ImageType::SOUND, ContentSettingsType::SOUND);
case ImageType::FRAMEBUST:
return std::make_unique<ContentSettingFramebustBlockImageModel>();
case ImageType::CLIPBOARD_READ_WRITE:
return std::make_unique<ContentSettingClipboardReadWriteImageModel>();
case ImageType::SENSORS:
return std::make_unique<ContentSettingSensorsImageModel>();
case ImageType::STORAGE_ACCESS:
return std::make_unique<ContentSettingStorageAccessImageModel>();
case ImageType::NOTIFICATIONS:
return std::make_unique<ContentSettingNotificationsImageModel>();
#if BUILDFLAG(IS_CHROMEOS)
case ImageType::SMART_CARD:
return std::make_unique<ContentSettingSmartCardImageModel>();
#endif
#if BUILDFLAG(IS_WIN)
case ImageType::PROTECTED_MEDIA_IDENTIFIER:
return std::make_unique<
ContentSettingProtectedMediaIdentifierImageModel>();
#endif // BUILDFLAG(IS_WIN)
case ImageType::NUM_IMAGE_TYPES:
break;
}
NOTREACHED();
}
void ContentSettingImageModel::Update(content::WebContents* contents) {
bool new_visibility = contents ? UpdateAndGetVisibility(contents) : false;
is_visible_ = new_visibility;
if (contents && !is_visible_) {
ContentSettingImageModelStates::Get(contents)->SetAnimationHasRun(
image_type(), false);
if (image_type_should_notify_accessibility_) {
ContentSettingImageModelStates::Get(contents)->SetAccessibilityNotified(
image_type(), false);
}
if (should_auto_open_bubble_) {
ContentSettingImageModelStates::Get(contents)->SetBubbleWasAutoOpened(
image_type(), false);
}
}
}
bool ContentSettingImageModel::ShouldRunAnimation(
content::WebContents* contents) {
DCHECK(contents);
return !ContentSettingImageModelStates::Get(contents)->AnimationHasRun(
image_type());
}
void ContentSettingImageModel::SetAnimationHasRun(
content::WebContents* contents) {
DCHECK(contents);
ContentSettingImageModelStates::Get(contents)->SetAnimationHasRun(
image_type(), true);
}
bool ContentSettingImageModel::ShouldNotifyAccessibility(
content::WebContents* contents) const {
return image_type_should_notify_accessibility_ &&
AccessibilityAnnouncementStringId() &&
!ContentSettingImageModelStates::Get(contents)
->GetAccessibilityNotified(image_type());
}
void ContentSettingImageModel::AccessibilityWasNotified(
content::WebContents* contents) {
ContentSettingImageModelStates::Get(contents)->SetAccessibilityNotified(
image_type(), true);
}
bool ContentSettingImageModel::ShouldAutoOpenBubble(
content::WebContents* contents) {
return should_auto_open_bubble_ &&
!ContentSettingImageModelStates::Get(contents)->BubbleWasAutoOpened(
image_type());
}
void ContentSettingImageModel::SetBubbleWasAutoOpened(
content::WebContents* contents) {
ContentSettingImageModelStates::Get(contents)->SetBubbleWasAutoOpened(
image_type(), true);
}
void ContentSettingImageModel::SetIcon(ContentSettingsType type, bool blocked) {
is_blocked_ = blocked;
GetIconFromType(type, blocked, &icon_, &icon_badge_);
}
void ContentSettingImageModel::SetFramebustBlockedIcon() {
icon_ = &kOpenInNewOffChromeRefreshIcon;
icon_badge_ = &gfx::VectorIcon::EmptyIcon();
}
// Generic blocked content settings --------------------------------------------
ContentSettingBlockedImageModel::ContentSettingBlockedImageModel(
ImageType image_type,
ContentSettingsType content_type)
: ContentSettingSimpleImageModel(image_type, content_type) {}
bool ContentSettingBlockedImageModel::UpdateAndGetVisibility(
WebContents* web_contents) {
const ContentSettingsType type = content_type();
const ContentSettingsImageDetails* image_details = GetImageDetails(type);
DCHECK(image_details) << "No entry for " << static_cast<int32_t>(type)
<< " in kImageDetails[].";
int tooltip_id = image_details->blocked_tooltip_id;
int explanation_id = image_details->blocked_explanatory_text_id;
// If a content type is blocked by default and was accessed, display the
// content blocked page action.
PageSpecificContentSettings* content_settings =
PageSpecificContentSettings::GetForFrame(
web_contents->GetPrimaryMainFrame());
if (!content_settings) {
return false;
}
bool is_blocked = content_settings->IsContentBlocked(type);
bool is_allowed = content_settings->IsContentAllowed(type);
if (!is_blocked && !is_allowed) {
return false;
}
Profile* profile =
Profile::FromBrowserContext(web_contents->GetBrowserContext());
auto* map = HostContentSettingsMapFactory::GetForProfile(profile);
if (type == ContentSettingsType::COOKIES) {
auto cookie_settings = CookieSettingsFactory::GetForProfile(profile);
const auto& url = web_contents->GetLastCommittedURL();
bool blocked_via_setting = cookie_settings->GetCookieSetting(
url, net::SiteForCookies::FromUrl(url), url,
{}) == CONTENT_SETTING_BLOCK;
// We check the cookie setting here as well because 3PC access influences
// the allowed/blocked status even though the icon is meant for 1PC control.
is_blocked = is_blocked && blocked_via_setting;
// True if the user blocked 1PCs by default but allowed them for this site.
bool allowed_for_site =
is_allowed && !blocked_via_setting &&
map->GetDefaultContentSetting(type) == CONTENT_SETTING_BLOCK;
// Only show the cookie page action if 1PCs are allowed via site-level
// exception on the current site OR blocked AND 3PCs are allowed.
if ((!allowed_for_site && !is_blocked) ||
cookie_settings->ShouldBlockThirdPartyCookies()) {
return false;
}
}
if (!is_blocked) {
tooltip_id = image_details->accessed_tooltip_id;
explanation_id = 0;
}
SetIcon(type, is_blocked);
set_explanatory_string_id(explanation_id);
DCHECK(tooltip_id);
set_tooltip(l10n_util::GetStringUTF16(tooltip_id));
return true;
}
// Geolocation -----------------------------------------------------------------
ContentSettingGeolocationImageModel::ContentSettingGeolocationImageModel()
: ContentSettingImageModel(ImageType::GEOLOCATION, kNotifyAccessibility) {}
ContentSettingGeolocationImageModel::~ContentSettingGeolocationImageModel() =
default;
bool ContentSettingGeolocationImageModel::UpdateAndGetVisibility(
WebContents* web_contents) {
PageSpecificContentSettings* content_settings =
PageSpecificContentSettings::GetForFrame(
web_contents->GetPrimaryMainFrame());
set_should_auto_open_bubble(false);
if (!content_settings) {
return false;
}
bool is_allowed =
content_settings->IsContentAllowed(ContentSettingsType::GEOLOCATION);
bool is_blocked =
content_settings->IsContentBlocked(ContentSettingsType::GEOLOCATION);
if (!is_allowed && !is_blocked) {
return false;
}
// Reset the explanatory string in all cases.
set_explanatory_string_id(0);
if (is_allowed) {
if (!system_permission_settings::IsAllowed(
ContentSettingsType::GEOLOCATION)) {
SetIcon(ContentSettingsType::GEOLOCATION, /*blocked=*/true);
base::RecordAction(base::UserMetricsAction(
"ContentSettings.Geolocation.BlockedIconShown"));
set_tooltip(l10n_util::GetStringUTF16(IDS_BLOCKED_GEOLOCATION_MESSAGE));
if (content_settings->geolocation_was_just_granted_on_site_level()) {
#if BUILDFLAG(IS_MAC) || BUILDFLAG(IS_WIN)
if (system_permission_settings::CanPrompt(
ContentSettingsType::GEOLOCATION)) {
// Ask the system to display a permission prompt for location access.
system_permission_settings::Request(ContentSettingsType::GEOLOCATION,
base::DoNothing());
} else {
// If the system permission is already denied then requesting the
// system permission will not show a prompt. Show the bubble instead.
set_should_auto_open_bubble(true);
}
#else
set_should_auto_open_bubble(true);
#endif // BUILDFLAG(IS_MAC) || BUILDFLAG(IS_WIN)
}
// At this point macOS may not have told us whether location permission
// has been allowed or blocked. Wait until the permission state is
// determined before displaying this message since it triggers an
// animation that cannot be cancelled
if (!system_permission_settings::CanPrompt(
ContentSettingsType::GEOLOCATION)) {
set_explanatory_string_id(IDS_GEOLOCATION_TURNED_OFF);
}
return true;
}
}
SetIcon(ContentSettingsType::GEOLOCATION, /*blocked=*/!is_allowed);
auto message_id = is_allowed ? IDS_ALLOWED_GEOLOCATION_MESSAGE
: IDS_BLOCKED_GEOLOCATION_MESSAGE;
set_tooltip(l10n_util::GetStringUTF16(message_id));
set_accessibility_string_id(message_id);
return true;
}
std::unique_ptr<ContentSettingBubbleModel>
ContentSettingGeolocationImageModel::CreateBubbleModelImpl(
ContentSettingBubbleModel::Delegate* delegate,
WebContents* web_contents) {
return std::make_unique<ContentSettingGeolocationBubbleModel>(delegate,
web_contents);
}
// Protocol handlers -----------------------------------------------------------
ContentSettingRPHImageModel::ContentSettingRPHImageModel()
: ContentSettingSimpleImageModel(ImageType::PROTOCOL_HANDLERS,
ContentSettingsType::PROTOCOL_HANDLERS) {
SetIcon(ContentSettingsType::PROTOCOL_HANDLERS, /*blocked=*/false);
set_tooltip(l10n_util::GetStringUTF16(IDS_REGISTER_PROTOCOL_HANDLER_TOOLTIP));
}
bool ContentSettingRPHImageModel::UpdateAndGetVisibility(
WebContents* web_contents) {
auto* content_settings_delegate =
PageSpecificContentSettingsDelegate::FromWebContents(web_contents);
if (!content_settings_delegate) {
return false;
}
if (content_settings_delegate->pending_protocol_handler().IsEmpty()) {
return false;
}
return true;
}
// MIDI SysEx ------------------------------------------------------------------
ContentSettingMIDISysExImageModel::ContentSettingMIDISysExImageModel()
: ContentSettingSimpleImageModel(ImageType::MIDI_SYSEX,
ContentSettingsType::MIDI_SYSEX) {}
bool ContentSettingMIDISysExImageModel::UpdateAndGetVisibility(
WebContents* web_contents) {
PageSpecificContentSettings* content_settings =
PageSpecificContentSettings::GetForFrame(
web_contents->GetPrimaryMainFrame());
if (!content_settings) {
return false;
}
const bool is_allowed =
content_settings->IsContentAllowed(ContentSettingsType::MIDI_SYSEX);
const bool is_blocked =
content_settings->IsContentBlocked(ContentSettingsType::MIDI_SYSEX);
if (!is_allowed && !is_blocked) {
return false;
}
SetIcon(ContentSettingsType::MIDI_SYSEX, /*blocked=*/!is_allowed);
set_tooltip(l10n_util::GetStringUTF16(is_allowed
? IDS_ALLOWED_MIDI_SYSEX_MESSAGE
: IDS_BLOCKED_MIDI_SYSEX_MESSAGE));
return true;
}
// Automatic downloads ---------------------------------------------------------
ContentSettingDownloadsImageModel::ContentSettingDownloadsImageModel()
: ContentSettingSimpleImageModel(ImageType::AUTOMATIC_DOWNLOADS,
ContentSettingsType::AUTOMATIC_DOWNLOADS) {
}
bool ContentSettingDownloadsImageModel::UpdateAndGetVisibility(
WebContents* web_contents) {
DownloadRequestLimiter* download_request_limiter =
g_browser_process->download_request_limiter();
// DownloadRequestLimiter can be absent in unit_tests.
if (!download_request_limiter) {
return false;
}
switch (download_request_limiter->GetDownloadUiStatus(web_contents)) {
case DownloadRequestLimiter::DOWNLOAD_UI_ALLOWED:
SetIcon(ContentSettingsType::AUTOMATIC_DOWNLOADS, /*blocked=*/false);
set_explanatory_string_id(0);
set_tooltip(l10n_util::GetStringUTF16(IDS_ALLOWED_DOWNLOAD_TITLE));
return true;
case DownloadRequestLimiter::DOWNLOAD_UI_BLOCKED:
SetIcon(ContentSettingsType::AUTOMATIC_DOWNLOADS, /*blocked=*/true);
set_explanatory_string_id(IDS_BLOCKED_DOWNLOADS_EXPLANATION);
set_tooltip(l10n_util::GetStringUTF16(IDS_BLOCKED_DOWNLOAD_TITLE));
return true;
case DownloadRequestLimiter::DOWNLOAD_UI_DEFAULT:
// No need to show icon otherwise.
return false;
}
}
// Clipboard -------------------------------------------------------------------
ContentSettingClipboardReadWriteImageModel::
ContentSettingClipboardReadWriteImageModel()
: ContentSettingSimpleImageModel(
ImageType::CLIPBOARD_READ_WRITE,
ContentSettingsType::CLIPBOARD_READ_WRITE) {}
bool ContentSettingClipboardReadWriteImageModel::UpdateAndGetVisibility(
WebContents* web_contents) {
PageSpecificContentSettings* content_settings =
PageSpecificContentSettings::GetForFrame(
web_contents->GetPrimaryMainFrame());
if (!content_settings) {
return false;
}
ContentSettingsType content_type = ContentSettingsType::CLIPBOARD_READ_WRITE;
bool blocked = content_settings->IsContentBlocked(content_type);
bool allowed = content_settings->IsContentAllowed(content_type);
if (!blocked && !allowed) {
return false;
}
SetIcon(ContentSettingsType::CLIPBOARD_READ_WRITE, /*blocked=*/!allowed);
set_tooltip(l10n_util::GetStringUTF16(
allowed ? IDS_ALLOWED_CLIPBOARD_MESSAGE : IDS_BLOCKED_CLIPBOARD_MESSAGE));
return true;
}
// Media -----------------------------------------------------------------------
ContentSettingMediaImageModel::ContentSettingMediaImageModel()
: ContentSettingImageModel(ImageType::MEDIASTREAM, kNotifyAccessibility) {}
bool ContentSettingMediaImageModel::UpdateAndGetVisibility(
WebContents* web_contents) {
// The system-level permission's state can be changed. Reset it before
// calculating the site-level permission's state.
set_blocked_on_system_level(false);
set_should_auto_open_bubble(false);
PageSpecificContentSettings* content_settings =
PageSpecificContentSettings::GetForFrame(
web_contents->GetPrimaryMainFrame());
if (!content_settings) {
return false;
}
state_ = content_settings->GetMicrophoneCameraState();
// If neither the microphone nor the camera stream was accessed then no icon
// is displayed in the omnibox.
if (state_.empty()) {
return false;
}
#if BUILDFLAG(IS_MAC)
// Don't show an icon when the user has not made a decision yet for
// the site level media permissions.
if (IsCameraAccessPendingOnSystemLevelPrompt() ||
IsMicAccessPendingOnSystemLevelPrompt()) {
return false;
}
set_explanatory_string_id(0);
if (IsCamAccessed() && IsMicAccessed()) {
if (IsCameraBlockedOnSiteLevel() || IsMicBlockedOnSiteLevel()) {
SetIcon(ContentSettingsType::MEDIASTREAM_CAMERA, /*blocked=*/true);
set_tooltip(l10n_util::GetStringUTF16(IDS_MICROPHONE_CAMERA_BLOCKED));
set_accessibility_string_id(IDS_MICROPHONE_CAMERA_BLOCKED);
} else if (DidCameraAccessFailBecauseOfSystemLevelBlock() ||
DidMicAccessFailBecauseOfSystemLevelBlock()) {
set_blocked_on_system_level(true);
SetIcon(ContentSettingsType::MEDIASTREAM_CAMERA, /*blocked=*/true);
set_tooltip(
l10n_util::GetStringUTF16(IDS_CAMERA_MIC_TURNED_OFF_IN_MACOS));
set_accessibility_string_id(IDS_CAMERA_MIC_TURNED_OFF_IN_MACOS);
if (content_settings->camera_was_just_granted_on_site_level() ||
content_settings->mic_was_just_granted_on_site_level()) {
// Automatically trigger the new bubble, if the camera
// and/or mic was just granted on a site level, but blocked on a
// system level.
set_should_auto_open_bubble(true);
} else {
set_explanatory_string_id(IDS_CAMERA_TURNED_OFF);
}
} else {
SetIcon(ContentSettingsType::MEDIASTREAM_CAMERA, /*blocked=*/false);
set_tooltip(l10n_util::GetStringUTF16(IDS_MICROPHONE_CAMERA_ALLOWED));
set_accessibility_string_id(IDS_MICROPHONE_CAMERA_ALLOWED);
}
return true;
}
if (IsCamAccessed()) {
if (IsCameraBlockedOnSiteLevel()) {
SetIcon(ContentSettingsType::MEDIASTREAM_CAMERA, /*blocked=*/true);
set_tooltip(l10n_util::GetStringUTF16(IDS_CAMERA_BLOCKED));
set_accessibility_string_id(IDS_CAMERA_BLOCKED);
} else if (DidCameraAccessFailBecauseOfSystemLevelBlock()) {
set_blocked_on_system_level(true);
SetIcon(ContentSettingsType::MEDIASTREAM_CAMERA, /*blocked=*/true);
set_tooltip(l10n_util::GetStringUTF16(IDS_CAMERA_TURNED_OFF_IN_MACOS));
set_accessibility_string_id(IDS_CAMERA_TURNED_OFF_IN_MACOS);
if (content_settings->camera_was_just_granted_on_site_level()) {
set_should_auto_open_bubble(true);
} else {
set_explanatory_string_id(IDS_CAMERA_TURNED_OFF);
}
} else {
SetIcon(ContentSettingsType::MEDIASTREAM_CAMERA, /*blocked=*/false);
set_tooltip(l10n_util::GetStringUTF16(IDS_CAMERA_ACCESSED));
set_accessibility_string_id(IDS_CAMERA_ACCESSED);
}
return true;
}
if (IsMicAccessed()) {
if (IsMicBlockedOnSiteLevel()) {
SetIcon(ContentSettingsType::MEDIASTREAM_MIC, /*blocked=*/true);
set_tooltip(l10n_util::GetStringUTF16(IDS_MICROPHONE_BLOCKED));
set_accessibility_string_id(IDS_MICROPHONE_BLOCKED);
} else if (DidMicAccessFailBecauseOfSystemLevelBlock()) {
set_blocked_on_system_level(true);
SetIcon(ContentSettingsType::MEDIASTREAM_MIC, /*blocked=*/true);
set_tooltip(l10n_util::GetStringUTF16(IDS_MIC_TURNED_OFF_IN_MACOS));
set_accessibility_string_id(IDS_MIC_TURNED_OFF_IN_MACOS);
if (content_settings->mic_was_just_granted_on_site_level()) {
set_should_auto_open_bubble(true);
} else {
set_explanatory_string_id(IDS_MIC_TURNED_OFF);
}
} else {
SetIcon(ContentSettingsType::MEDIASTREAM_MIC, /*blocked=*/false);
set_tooltip(l10n_util::GetStringUTF16(IDS_MICROPHONE_ACCESSED));
set_accessibility_string_id(IDS_MICROPHONE_ACCESSED);
}
return true;
}
#endif // BUILDFLAG(IS_MAC)
DCHECK(IsMicAccessed() || IsCamAccessed());
int id = IDS_CAMERA_BLOCKED;
if (IsMicBlockedOnSiteLevel() || IsCameraBlockedOnSiteLevel()) {
if (IsMicAccessed()) {
id = IsCamAccessed() ? IDS_MICROPHONE_CAMERA_BLOCKED
: IDS_MICROPHONE_BLOCKED;
}
if (IsCamAccessed()) {
SetIcon(ContentSettingsType::MEDIASTREAM_CAMERA, /*blocked=*/true);
} else {
SetIcon(ContentSettingsType::MEDIASTREAM_MIC, /*blocked=*/true);
}
} else {
SetIcon(ContentSettingsType::MEDIASTREAM_CAMERA, /*blocked=*/false);
id = IDS_CAMERA_ACCESSED;
if (IsMicAccessed()) {
id = IsCamAccessed() ? IDS_MICROPHONE_CAMERA_ALLOWED
: IDS_MICROPHONE_ACCESSED;
}
if (IsCamAccessed()) {
SetIcon(ContentSettingsType::MEDIASTREAM_CAMERA, /*blocked=*/false);
} else {
SetIcon(ContentSettingsType::MEDIASTREAM_MIC, /*blocked=*/false);
}
}
set_tooltip(l10n_util::GetStringUTF16(id));
set_accessibility_string_id(id);
return true;
}
bool ContentSettingMediaImageModel::IsMicAccessed() {
return state_.Has(PageSpecificContentSettings::kMicrophoneAccessed);
}
bool ContentSettingMediaImageModel::IsCamAccessed() {
return state_.Has(PageSpecificContentSettings::kCameraAccessed);
}
bool ContentSettingMediaImageModel::IsMicBlockedOnSiteLevel() {
return state_.Has(PageSpecificContentSettings::kMicrophoneBlocked);
}
bool ContentSettingMediaImageModel::IsCameraBlockedOnSiteLevel() {
return state_.Has(PageSpecificContentSettings::kCameraBlocked);
}
#if BUILDFLAG(IS_MAC)
bool ContentSettingMediaImageModel::
DidCameraAccessFailBecauseOfSystemLevelBlock() {
return (IsCamAccessed() && !IsCameraBlockedOnSiteLevel() &&
system_permission_settings::CheckSystemVideoCapturePermission() ==
system_permission_settings::SystemPermission::kDenied);
}
bool ContentSettingMediaImageModel::
DidMicAccessFailBecauseOfSystemLevelBlock() {
return (IsMicAccessed() && !IsMicBlockedOnSiteLevel() &&
system_permission_settings::CheckSystemAudioCapturePermission() ==
system_permission_settings::SystemPermission::kDenied);
}
bool ContentSettingMediaImageModel::IsCameraAccessPendingOnSystemLevelPrompt() {
return (system_permission_settings::CheckSystemVideoCapturePermission() ==
system_permission_settings::SystemPermission::kNotDetermined &&
IsCamAccessed() && !IsCameraBlockedOnSiteLevel());
}
bool ContentSettingMediaImageModel::IsMicAccessPendingOnSystemLevelPrompt() {
return (system_permission_settings::CheckSystemAudioCapturePermission() ==
system_permission_settings::SystemPermission::kNotDetermined &&
IsMicAccessed() && !IsMicBlockedOnSiteLevel());
}
#endif // BUILDFLAG(IS_MAC)
std::unique_ptr<ContentSettingBubbleModel>
ContentSettingMediaImageModel::CreateBubbleModelImpl(
ContentSettingBubbleModel::Delegate* delegate,
WebContents* web_contents) {
return std::make_unique<ContentSettingMediaStreamBubbleModel>(delegate,
web_contents);
}
// Blocked Framebust -----------------------------------------------------------
ContentSettingFramebustBlockImageModel::ContentSettingFramebustBlockImageModel()
: ContentSettingImageModel(ImageType::FRAMEBUST) {}
bool ContentSettingFramebustBlockImageModel::UpdateAndGetVisibility(
WebContents* web_contents) {
// Early exit if no blocked Framebust.
if (!FramebustBlockTabHelper::FromWebContents(web_contents)
->HasBlockedUrls()) {
return false;
}
SetFramebustBlockedIcon();
set_explanatory_string_id(IDS_REDIRECT_BLOCKED_TITLE);
set_tooltip(l10n_util::GetStringUTF16(IDS_REDIRECT_BLOCKED_TOOLTIP));
return true;
}
std::unique_ptr<ContentSettingBubbleModel>
ContentSettingFramebustBlockImageModel::CreateBubbleModelImpl(
ContentSettingBubbleModel::Delegate* delegate,
WebContents* web_contents) {
return std::make_unique<ContentSettingFramebustBlockBubbleModel>(
delegate, web_contents);
}
// Sensors ---------------------------------------------------------------------
ContentSettingSensorsImageModel::ContentSettingSensorsImageModel()
: ContentSettingSimpleImageModel(ImageType::SENSORS,
ContentSettingsType::SENSORS) {}
bool ContentSettingSensorsImageModel::UpdateAndGetVisibility(
WebContents* web_contents) {
auto* content_settings = PageSpecificContentSettings::GetForFrame(
web_contents->GetPrimaryMainFrame());
if (!content_settings) {
return false;
}
bool blocked = content_settings->IsContentBlocked(content_type());
bool allowed = content_settings->IsContentAllowed(content_type());
if (!blocked && !allowed) {
return false;
}
HostContentSettingsMap* map = HostContentSettingsMapFactory::GetForProfile(
Profile::FromBrowserContext(web_contents->GetBrowserContext()));
// Do not show any indicator if sensors are allowed by default and they were
// not blocked in this page.
if (!blocked && map->GetDefaultContentSetting(content_type(), nullptr) ==
CONTENT_SETTING_ALLOW) {
return false;
}
SetIcon(ContentSettingsType::SENSORS, /*blocked=*/blocked);
if (base::FeatureList::IsEnabled(features::kGenericSensorExtraClasses)) {
set_tooltip(l10n_util::GetStringUTF16(
!blocked ? IDS_SENSORS_ALLOWED_TOOLTIP : IDS_SENSORS_BLOCKED_TOOLTIP));
} else {
set_tooltip(l10n_util::GetStringUTF16(
!blocked ? IDS_MOTION_SENSORS_ALLOWED_TOOLTIP
: IDS_MOTION_SENSORS_BLOCKED_TOOLTIP));
}
return true;
}
// Popups ---------------------------------------------------------------------
ContentSettingPopupImageModel::ContentSettingPopupImageModel()
: ContentSettingSimpleImageModel(ImageType::POPUPS,
ContentSettingsType::POPUPS) {}
bool ContentSettingPopupImageModel::UpdateAndGetVisibility(
WebContents* web_contents) {
PageSpecificContentSettings* content_settings =
PageSpecificContentSettings::GetForFrame(
web_contents->GetPrimaryMainFrame());
if (!content_settings ||
!content_settings->IsContentBlocked(content_type())) {
return false;
}
SetIcon(ContentSettingsType::POPUPS, /*blocked=*/true);
set_explanatory_string_id(IDS_BLOCKED_POPUPS_EXPLANATORY_TEXT);
set_tooltip(l10n_util::GetStringUTF16(IDS_BLOCKED_POPUPS_TOOLTIP));
return true;
}
// Storage Access
// ---------------------------------------------------------------------
ContentSettingStorageAccessImageModel::ContentSettingStorageAccessImageModel()
: ContentSettingSimpleImageModel(ImageType::STORAGE_ACCESS,
ContentSettingsType::STORAGE_ACCESS) {}
bool ContentSettingStorageAccessImageModel::UpdateAndGetVisibility(
WebContents* web_contents) {
PageSpecificContentSettings* content_settings =
PageSpecificContentSettings::GetForFrame(
web_contents->GetPrimaryMainFrame());
if (!content_settings) {
return false;
}
std::map<net::SchemefulSite, bool> entries =
content_settings->GetTwoSiteRequests(content_type());
if (entries.empty()) {
return false;
}
bool has_blocked_requests =
std::ranges::any_of(entries, [](auto& entry) { return !entry.second; });
SetIcon(ContentSettingsType::STORAGE_ACCESS,
/*blocked=*/has_blocked_requests);
// set_explanatory_string_id(IDS_BLOCKED_POPUPS_EXPLANATORY_TEXT);
set_tooltip(l10n_util::GetStringUTF16(
has_blocked_requests ? IDS_STORAGE_ACCESS_PERMISSION_BLOCKED_TOOLTIP
: IDS_STORAGE_ACCESS_PERMISSION_ALLOWED_TOOLTIP));
return true;
}
// Notifications --------------------------------------------------------------
ContentSettingNotificationsImageModel::ContentSettingNotificationsImageModel()
: ContentSettingSimpleImageModel(
ImageType::NOTIFICATIONS,
ContentSettingsType::NOTIFICATIONS,
true /* image_type_should_notify_accessibility */) {
SetIcon(ContentSettingsType::NOTIFICATIONS, /*blocked=*/false);
set_tooltip(
l10n_util::GetStringUTF16(IDS_NOTIFICATIONS_OFF_EXPLANATORY_TEXT));
}
bool ContentSettingNotificationsImageModel::UpdateAndGetVisibility(
WebContents* web_contents) {
set_should_auto_open_bubble(false);
set_blocked_on_system_level(false);
#if BUILDFLAG(IS_MAC)
if (std::optional<webapps::AppId> app_id =
web_app::WebAppTabHelper::GetAppIdForNotificationAttribution(
web_contents);
app_id.has_value()) {
PageSpecificContentSettings* content_settings =
PageSpecificContentSettings::GetForFrame(
web_contents->GetPrimaryMainFrame());
const bool is_allowed =
content_settings &&
content_settings->IsContentAllowed(ContentSettingsType::NOTIFICATIONS);
const bool was_denied_because_of_system_permission =
content_settings &&
content_settings
->notifications_was_denied_because_of_system_permission();
const mac_notifications::mojom::PermissionStatus system_permission_status =
AppShimRegistry::Get()->GetNotificationPermissionStatusForApp(*app_id);
// If the system level permission for this app is currently "denied", and
// either the chrome level permission was granted (and notifications have
// been attempted to be used in this page) or the chrome level permission
// just switched from "ask" to "blocked", show the indicator icon.
if ((was_denied_because_of_system_permission || is_allowed) &&
system_permission_status ==
mac_notifications::mojom::PermissionStatus::kDenied) {
SetIcon(ContentSettingsType::NOTIFICATIONS, /*blocked=*/true);
// If the chrome level permission was just auto-denied, also popup the
// bubble.
set_should_auto_open_bubble(was_denied_because_of_system_permission);
set_blocked_on_system_level(true);
return true;
}
}
#endif
auto* manager =
permissions::PermissionRequestManager::FromWebContents(web_contents);
// We shouldn't show the icon unless we're a PWA.
// TODO(crbug.com/40186737): Allow PermissionRequestManager to identify the
// correct UI style of a permission prompt.
const bool quiet_icon_allowed = web_app::AppBrowserController::IsWebApp(
chrome::FindBrowserWithTab(web_contents));
if (!quiet_icon_allowed || !manager ||
!manager->ShouldCurrentRequestUseQuietUI()) {
return false;
}
// |manager| may be null in tests.
SetIcon(ContentSettingsType::NOTIFICATIONS, /*blocked=*/false);
if (permissions::PermissionUiSelector::ShouldSuppressAnimation(
manager->ReasonForUsingQuietUi())) {
set_accessibility_string_id(IDS_NOTIFICATIONS_OFF_EXPLANATORY_TEXT);
set_explanatory_string_id(0);
} else {
set_explanatory_string_id(IDS_NOTIFICATIONS_OFF_EXPLANATORY_TEXT);
}
return true;
}
std::unique_ptr<ContentSettingBubbleModel>
ContentSettingNotificationsImageModel::CreateBubbleModelImpl(
ContentSettingBubbleModel::Delegate* delegate,
WebContents* web_contents) {
if (blocked_on_system_level()) {
#if BUILDFLAG(IS_MAC)
return std::make_unique<ContentSettingNotificationsBubbleModel>(
delegate, web_contents);
#else
NOTREACHED();
#endif
} else {
return std::make_unique<ContentSettingQuietRequestBubbleModel>(
delegate, web_contents);
}
}
#if BUILDFLAG(IS_WIN)
// Protected media identifiers
// -------------------------------------------------------------------
ContentSettingProtectedMediaIdentifierImageModel::
ContentSettingProtectedMediaIdentifierImageModel()
: ContentSettingSimpleImageModel(
ImageType::PROTECTED_MEDIA_IDENTIFIER,
ContentSettingsType::PROTECTED_MEDIA_IDENTIFIER,
/*image_type_should_notify_accessibility=*/true) {}
bool ContentSettingProtectedMediaIdentifierImageModel::UpdateAndGetVisibility(
WebContents* web_contents) {
PageSpecificContentSettings* content_settings =
PageSpecificContentSettings::GetForFrame(
web_contents->GetPrimaryMainFrame());
if (!content_settings) {
return false;
}
ContentSettingsType content_type =
ContentSettingsType::PROTECTED_MEDIA_IDENTIFIER;
bool blocked = content_settings->IsContentBlocked(content_type);
bool allowed = content_settings->IsContentAllowed(content_type);
if (!blocked && !allowed) {
return false;
}
SetIcon(ContentSettingsType::PROTECTED_MEDIA_IDENTIFIER,
/*blocked=*/!allowed);
auto message_id = allowed ? IDS_ALLOWED_PROTECTED_CONTENT_IDENTIFIERS_MESSAGE
: IDS_BLOCKED_PROTECTED_CONTENT_IDENTIFIERS_MESSAGE;
set_tooltip(l10n_util::GetStringUTF16(message_id));
set_accessibility_string_id(message_id);
return true;
}
#endif // BUILDFLAG(IS_WIN)
// Base class ------------------------------------------------------------------
gfx::Image ContentSettingImageModel::GetIcon(SkColor icon_color) const {
int icon_size =
icon_size_.value_or(GetLayoutConstant(LOCATION_BAR_TRAILING_ICON_SIZE));
return gfx::Image(gfx::CreateVectorIconWithBadge(*icon_, icon_size,
icon_color, *icon_badge_));
}
void ContentSettingImageModel::SetIconSize(int icon_size) {
icon_size_ = icon_size;
}
int ContentSettingImageModel::AccessibilityAnnouncementStringId() const {
// This method should return `accessibility_string_id_` if it is set.
// Otherwise `explanatory_string_id_` can be used for an announcement as well.
return accessibility_string_id_ ? accessibility_string_id_
: explanatory_string_id_;
}
ContentSettingImageModel::ContentSettingImageModel(
ImageType image_type,
bool image_type_should_notify_accessibility)
: icon_(&gfx::VectorIcon::EmptyIcon()),
icon_badge_(&gfx::VectorIcon::EmptyIcon()),
image_type_(image_type),
image_type_should_notify_accessibility_(
image_type_should_notify_accessibility) {}
std::unique_ptr<ContentSettingBubbleModel>
ContentSettingImageModel::CreateBubbleModel(
ContentSettingBubbleModel::Delegate* delegate,
content::WebContents* web_contents) {
DCHECK(web_contents);
return CreateBubbleModelImpl(delegate, web_contents);
}
// static
std::vector<std::unique_ptr<ContentSettingImageModel>>
ContentSettingImageModel::GenerateContentSettingImageModels() {
// The ordering of the models here influences the order in which icons are
// shown in the omnibox.
constexpr ImageType kContentSettingImageOrder[] = {
ImageType::COOKIES,
ImageType::IMAGES,
ImageType::JAVASCRIPT,
ImageType::POPUPS,
ImageType::GEOLOCATION,
ImageType::MIXEDSCRIPT,
ImageType::PROTOCOL_HANDLERS,
ImageType::MEDIASTREAM,
ImageType::SENSORS,
ImageType::ADS,
ImageType::AUTOMATIC_DOWNLOADS,
ImageType::MIDI_SYSEX,
ImageType::SOUND,
ImageType::FRAMEBUST,
ImageType::CLIPBOARD_READ_WRITE,
ImageType::NOTIFICATIONS,
ImageType::STORAGE_ACCESS,
#if BUILDFLAG(IS_CHROMEOS)
ImageType::SMART_CARD,
#endif
#if BUILDFLAG(IS_WIN)
ImageType::PROTECTED_MEDIA_IDENTIFIER,
#endif
};
std::vector<std::unique_ptr<ContentSettingImageModel>> result;
for (auto type : kContentSettingImageOrder) {
#if BUILDFLAG(IS_WIN)
if (type == ImageType::PROTECTED_MEDIA_IDENTIFIER &&
!base::FeatureList::IsEnabled(
media::kProtectedMediaIdentifierIndicator)) {
continue;
}
#endif
result.push_back(CreateForContentType(type));
}
return result;
}
// static
size_t ContentSettingImageModel::GetContentSettingImageModelIndexForTesting(
ImageType image_type) {
std::vector<std::unique_ptr<ContentSettingImageModel>> models =
GenerateContentSettingImageModels();
for (size_t i = 0; i < models.size(); ++i) {
if (image_type == models[i]->image_type()) {
return i;
}
}
NOTREACHED();
}