blob: 4431a12a317fb372d46c3832e901a206a0347c70 [file] [log] [blame]
// Copyright 2021 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/safe_browsing/tailored_security/notification_handler_desktop.h"
#include "base/metrics/histogram_functions.h"
#include "chrome/app/vector_icons/vector_icons.h"
#include "chrome/browser/notifications/notification_display_service.h"
#include "chrome/browser/notifications/notification_display_service_factory.h"
#include "chrome/browser/notifications/notification_handler.h"
#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/safe_browsing/tailored_security/tailored_security_outcome.h"
#include "chrome/browser/ui/browser.h"
#include "chrome/browser/ui/browser_finder.h"
#include "chrome/browser/ui/browser_window.h"
#include "chrome/browser/ui/chrome_pages.h"
#include "chrome/browser/ui/scoped_tabbed_browser_displayer.h"
#include "chrome/grit/chromium_strings.h"
#include "chrome/grit/generated_resources.h"
#include "components/prefs/pref_service.h"
#include "components/safe_browsing/core/common/safe_browsing_prefs.h"
#include "components/strings/grit/components_strings.h"
#include "components/vector_icons/vector_icons.h"
#include "content/public/common/referrer.h"
#include "ui/base/l10n/l10n_util.h"
#include "ui/base/page_transition_types.h"
#include "ui/base/window_open_disposition.h"
#include "ui/color/color_provider.h"
#include "ui/message_center/public/cpp/message_center_constants.h"
#include "ui/message_center/public/cpp/notification.h"
#include "ui/native_theme/common_theme.h"
#include "ui/native_theme/native_theme.h"
namespace safe_browsing {
namespace {
const char kTailoredSecurityEnableNotificationId[] =
"TailoredSecurityEnableNotification";
const char kTailoredSecurityDisableNotificationId[] =
"TailoredSecurityDisableNotification";
const char kTailoredSecurityUnconsentedPromotionNotificationId[] =
"TailoredSecurityUnconsentedPromotionNotification";
const char kTailoredSecurityNotifierId[] =
"chrome://settings/security/notification/id-notifier";
const char kTailoredSecurityNotificationOrigin[] =
"chrome://settings/security?q=enhanced";
// |is_esb_enabled_in_sync| records if ESB was enabled in sync with Account-ESB
void ChangeSafeBrowsingStateAndOpenSettings(Profile* profile,
SafeBrowsingState new_state,
bool is_esb_enabled_in_sync) {
SetSafeBrowsingState(profile->GetPrefs(), new_state, is_esb_enabled_in_sync);
Browser* browser = chrome::ScopedTabbedBrowserDisplayer(profile).browser();
chrome::ShowSafeBrowsingEnhancedProtection(browser);
}
void LogConsentedOutcome(TailoredSecurityOutcome outcome, bool enable) {
if (enable) {
base::UmaHistogramEnumeration(
"SafeBrowsing.TailoredSecurityConsentedEnabledNotificationOutcome",
outcome);
} else {
base::UmaHistogramEnumeration(
"SafeBrowsing.TailoredSecurityConsentedDisabledNotificationOutcome",
outcome);
}
}
void LogUnconsentedOutcome(TailoredSecurityOutcome outcome) {
base::UmaHistogramEnumeration(
"SafeBrowsing.TailoredSecurityUnconsentedPromotionNotificationOutcome",
outcome);
}
} // namespace
TailoredSecurityNotificationHandler::TailoredSecurityNotificationHandler() =
default;
TailoredSecurityNotificationHandler::~TailoredSecurityNotificationHandler() =
default;
void TailoredSecurityNotificationHandler::OnClose(
Profile* profile,
const GURL& origin,
const std::string& notification_id,
bool by_user,
base::OnceClosure completed_closure) {
if (notification_id == kTailoredSecurityUnconsentedPromotionNotificationId) {
LogUnconsentedOutcome(TailoredSecurityOutcome::kDismissed);
} else {
bool is_enable = (notification_id == kTailoredSecurityEnableNotificationId);
LogConsentedOutcome(TailoredSecurityOutcome::kDismissed, is_enable);
}
std::move(completed_closure).Run();
}
void TailoredSecurityNotificationHandler::OnClick(
Profile* profile,
const GURL& origin,
const std::string& notification_id,
const absl::optional<int>& action_index,
const absl::optional<std::u16string>& reply,
base::OnceClosure completed_closure) {
if (!action_index) {
std::move(completed_closure).Run();
return;
}
if (notification_id == kTailoredSecurityUnconsentedPromotionNotificationId) {
if (*action_index == 0) {
LogUnconsentedOutcome(TailoredSecurityOutcome::kAccepted);
chrome::ShowSafeBrowsingEnhancedProtection(
chrome::ScopedTabbedBrowserDisplayer(profile).browser());
} else {
LogUnconsentedOutcome(TailoredSecurityOutcome::kRejected);
}
} else {
bool is_enable = (notification_id == kTailoredSecurityEnableNotificationId);
if (*action_index == 0) {
// Enable: Pressed Turn on, Disable: Pressed Turn off. Both are
// acceptance
LogConsentedOutcome(TailoredSecurityOutcome::kAccepted, is_enable);
if (is_enable) {
ChangeSafeBrowsingStateAndOpenSettings(
profile, SafeBrowsingState::ENHANCED_PROTECTION,
/*is_esb_enabled_in_sync=*/true);
} else {
ChangeSafeBrowsingStateAndOpenSettings(
profile, SafeBrowsingState::STANDARD_PROTECTION,
/*is_esb_enabled_in_sync=*/false);
}
} else {
// Both enable and disable dialogs display No Thanks, and are rejecting.
LogConsentedOutcome(TailoredSecurityOutcome::kRejected, is_enable);
}
}
std::move(completed_closure).Run();
}
void DisplayTailoredSecurityConsentedModalDesktop(Profile* profile,
bool enable) {
Browser* browser = chrome::FindLastActiveWithProfile(profile);
if (!browser)
return;
const ui::ColorProvider* color_provider =
browser->window()->GetColorProvider();
std::u16string title, description, primary_button, secondary_button;
gfx::Image icon;
std::string notification_id;
if (enable) {
notification_id = kTailoredSecurityEnableNotificationId;
title = l10n_util::GetStringUTF16(
IDS_TAILORED_SECURITY_CONSENTED_ENABLE_NOTIFICATION_TITLE);
description = l10n_util::GetStringUTF16(
IDS_TAILORED_SECURITY_CONSENTED_ENABLE_NOTIFICATION_DESCRIPTION);
primary_button = l10n_util::GetStringUTF16(
IDS_TAILORED_SECURITY_CONSENTED_ENABLE_NOTIFICATION_ACCEPT);
secondary_button = l10n_util::GetStringUTF16(IDS_NO_THANKS);
// TODO(crbug/1257621): Confirm with UX that it's appropriate to use the
// blue color here.
SkColor icon_color = color_provider->GetColor(ui::kColorAccent);
icon = gfx::Image(gfx::CreateVectorIcon(
kSafetyCheckIcon, message_center::kNotificationIconSize, icon_color));
} else {
notification_id = kTailoredSecurityDisableNotificationId;
title = l10n_util::GetStringUTF16(
IDS_TAILORED_SECURITY_CONSENTED_DISABLE_NOTIFICATION_TITLE);
description = l10n_util::GetStringUTF16(
IDS_TAILORED_SECURITY_CONSENTED_DISABLE_NOTIFICATION_DESCRIPTION);
primary_button = l10n_util::GetStringUTF16(
IDS_TAILORED_SECURITY_CONSENTED_DISABLE_NOTIFICATION_TURN_OFF);
secondary_button = l10n_util::GetStringUTF16(IDS_NO_THANKS);
SkColor icon_color =
color_provider->GetColor(ui::kColorSecondaryForeground);
icon = gfx::Image(gfx::CreateVectorIcon(
vector_icons::kGppMaybeIcon, message_center::kNotificationIconSize,
icon_color));
}
LogConsentedOutcome(TailoredSecurityOutcome::kShown, enable);
message_center::Notification notification(
message_center::NOTIFICATION_TYPE_SIMPLE, notification_id, title,
description, icon,
l10n_util::GetStringUTF16(IDS_TAILORED_SECURITY_DISPLAY_SOURCE),
GURL(kTailoredSecurityNotificationOrigin),
message_center::NotifierId(message_center::NotifierType::SYSTEM_COMPONENT,
kTailoredSecurityNotifierId),
message_center::RichNotificationData(),
/*delegate=*/nullptr);
notification.set_buttons({message_center::ButtonInfo(primary_button),
message_center::ButtonInfo(secondary_button)});
NotificationDisplayServiceFactory::GetForProfile(profile)->Display(
NotificationHandler::Type::TAILORED_SECURITY, notification,
/*metadata=*/nullptr);
}
void DisplayTailoredSecurityUnconsentedPromotionNotification(Profile* profile) {
Browser* browser = chrome::FindLastActiveWithProfile(profile);
if (!browser)
return;
const ui::ColorProvider* color_provider =
browser->window()->GetColorProvider();
std::string notification_id =
kTailoredSecurityUnconsentedPromotionNotificationId;
const std::u16string& title = l10n_util::GetStringUTF16(
IDS_TAILORED_SECURITY_UNCONSENTED_PROMOTION_NOTIFICATION_TITLE);
const std::u16string& description = l10n_util::GetStringUTF16(
IDS_TAILORED_SECURITY_UNCONSENTED_PROMOTION_NOTIFICATION_DESCRIPTION);
const std::u16string& primary_button = l10n_util::GetStringUTF16(
IDS_TAILORED_SECURITY_UNCONSENTED_PROMOTION_NOTIFICATION_ACCEPT);
const std::u16string& secondary_button =
l10n_util::GetStringUTF16(IDS_NO_THANKS);
// TODO(crbug/1257622): Confirm with UX that it's appropriate to use the
// blue color here.
SkColor icon_color = color_provider->GetColor(ui::kColorAccent);
gfx::Image icon = gfx::Image(gfx::CreateVectorIcon(
kSafetyCheckIcon, message_center::kNotificationIconSize, icon_color));
LogUnconsentedOutcome(TailoredSecurityOutcome::kShown);
message_center::Notification notification(
message_center::NOTIFICATION_TYPE_SIMPLE, notification_id, title,
description, icon,
l10n_util::GetStringUTF16(IDS_TAILORED_SECURITY_DISPLAY_SOURCE),
GURL(kTailoredSecurityNotificationOrigin),
message_center::NotifierId(message_center::NotifierType::SYSTEM_COMPONENT,
kTailoredSecurityNotifierId),
message_center::RichNotificationData(),
/*delegate=*/nullptr);
notification.set_buttons({message_center::ButtonInfo(primary_button),
message_center::ButtonInfo(secondary_button)});
NotificationDisplayServiceFactory::GetForProfile(profile)->Display(
NotificationHandler::Type::TAILORED_SECURITY, notification,
/*metadata=*/nullptr);
}
} // namespace safe_browsing