Commit 08c9c0c5 authored by Aya ElAttar's avatar Aya ElAttar Committed by Commit Bot

DLP: Bubble instead of toasts for clipboard

- Changed the toasts shown for clipboard blocked pastes
to bubbles according to the new mocks.
- Moved all the clipboard notifications related
functions to dlp_clipboard_notification_helper.h/.cc

Bug: 1148224, 1131670
Change-Id: I69a99b1a99d08cbc6ea47852d3ce6a3a7fdace66
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2532564
Commit-Queue: Aya Elsayed <ayaelattar@chromium.org>
Reviewed-by: default avatarAya Elsayed <ayaelattar@chromium.org>
Reviewed-by: default avatarSergey Poromov <poromov@chromium.org>
Reviewed-by: default avatarNikita Podguzov <nikitapodguzov@chromium.org>
Reviewed-by: default avatarAvi Drissman <avi@chromium.org>
Reviewed-by: default avatarAhmed Fakhry <afakhry@chromium.org>
Cr-Commit-Position: refs/heads/master@{#829162}
parent e35022a3
...@@ -2195,6 +2195,8 @@ source_set("chromeos") { ...@@ -2195,6 +2195,8 @@ source_set("chromeos") {
"policy/display_settings_handler.h", "policy/display_settings_handler.h",
"policy/dlp/data_transfer_dlp_controller.cc", "policy/dlp/data_transfer_dlp_controller.cc",
"policy/dlp/data_transfer_dlp_controller.h", "policy/dlp/data_transfer_dlp_controller.h",
"policy/dlp/dlp_clipboard_notification_helper.cc",
"policy/dlp/dlp_clipboard_notification_helper.h",
"policy/dlp/dlp_content_manager.cc", "policy/dlp/dlp_content_manager.cc",
"policy/dlp/dlp_content_manager.h", "policy/dlp/dlp_content_manager.h",
"policy/dlp/dlp_content_restriction_set.cc", "policy/dlp/dlp_content_restriction_set.cc",
......
...@@ -6,32 +6,15 @@ ...@@ -6,32 +6,15 @@
#include <vector> #include <vector>
#include "ash/public/cpp/toast_data.h"
#include "ash/public/cpp/toast_manager.h"
#include "base/notreached.h" #include "base/notreached.h"
#include "base/optional.h"
#include "base/strings/utf_string_conversions.h"
#include "chrome/browser/browser_process.h"
#include "chrome/browser/chromeos/crostini/crostini_util.h"
#include "chrome/browser/chromeos/plugin_vm/plugin_vm_util.h"
#include "chrome/browser/chromeos/policy/dlp/dlp_rules_manager.h" #include "chrome/browser/chromeos/policy/dlp/dlp_rules_manager.h"
#include "chrome/browser/profiles/profile_manager.h" #include "chrome/browser/profiles/profile_manager.h"
#include "chrome/grit/generated_resources.h"
#include "components/strings/grit/components_strings.h"
#include "ui/base/clipboard/clipboard.h" #include "ui/base/clipboard/clipboard.h"
#include "ui/base/data_transfer_policy/data_transfer_endpoint.h" #include "ui/base/data_transfer_policy/data_transfer_endpoint.h"
#include "ui/base/l10n/l10n_util.h"
#include "url/gurl.h" #include "url/gurl.h"
namespace policy { namespace policy {
namespace {
const char kToastId[] = "clipboard_dlp_block";
constexpr int kToastDurationMs = 2500;
} // namespace
// static // static
void DataTransferDlpController::Init() { void DataTransferDlpController::Init() {
if (!HasInstance()) if (!HasInstance())
...@@ -40,7 +23,7 @@ void DataTransferDlpController::Init() { ...@@ -40,7 +23,7 @@ void DataTransferDlpController::Init() {
bool DataTransferDlpController::IsDataReadAllowed( bool DataTransferDlpController::IsDataReadAllowed(
const ui::DataTransferEndpoint* const data_src, const ui::DataTransferEndpoint* const data_src,
const ui::DataTransferEndpoint* const data_dst) const { const ui::DataTransferEndpoint* const data_dst) {
if (!data_src || data_src->type() == ui::EndpointType::kClipboardHistory) { if (!data_src || data_src->type() == ui::EndpointType::kClipboardHistory) {
return true; return true;
} }
...@@ -75,7 +58,7 @@ bool DataTransferDlpController::IsDataReadAllowed( ...@@ -75,7 +58,7 @@ bool DataTransferDlpController::IsDataReadAllowed(
bool notify_on_paste = !data_dst || data_dst->notify_if_restricted(); bool notify_on_paste = !data_dst || data_dst->notify_if_restricted();
if (level == DlpRulesManager::Level::kBlock && notify_on_paste) { if (level == DlpRulesManager::Level::kBlock && notify_on_paste) {
ShowBlockToast(GetToastText(data_src, data_dst)); helper_.NotifyBlockedPaste(data_src, data_dst);
} }
return level == DlpRulesManager::Level::kAllow; return level == DlpRulesManager::Level::kAllow;
...@@ -85,55 +68,4 @@ DataTransferDlpController::DataTransferDlpController() = default; ...@@ -85,55 +68,4 @@ DataTransferDlpController::DataTransferDlpController() = default;
DataTransferDlpController::~DataTransferDlpController() = default; DataTransferDlpController::~DataTransferDlpController() = default;
void DataTransferDlpController::ShowBlockToast(
const base::string16& text) const {
ash::ToastData toast(kToastId, text, kToastDurationMs, base::nullopt);
toast.is_managed = true;
ash::ToastManager::Get()->Show(toast);
}
base::string16 DataTransferDlpController::GetToastText(
const ui::DataTransferEndpoint* const data_src,
const ui::DataTransferEndpoint* const data_dst) const {
DCHECK(data_src);
DCHECK(data_src->origin());
base::string16 host_name = base::UTF8ToUTF16(data_src->origin()->host());
if (data_dst && data_dst->type() == ui::EndpointType::kGuestOs) {
ProfileManager* profile_manager = g_browser_process->profile_manager();
Profile* profile =
profile_manager ? profile_manager->GetActiveUserProfile() : nullptr;
bool is_crostini_running = crostini::IsCrostiniRunning(profile);
bool is_plugin_vm_running = plugin_vm::IsPluginVmRunning(profile);
if (is_crostini_running && is_plugin_vm_running) {
return l10n_util::GetStringFUTF16(
IDS_POLICY_DLP_CLIPBOARD_BLOCKED_ON_COPY_TWO_VMS, host_name,
l10n_util::GetStringUTF16(IDS_CROSTINI_LINUX),
l10n_util::GetStringUTF16(IDS_PLUGIN_VM_APP_NAME));
} else if (is_crostini_running) {
return l10n_util::GetStringFUTF16(
IDS_POLICY_DLP_CLIPBOARD_BLOCKED_ON_COPY_VM, host_name,
l10n_util::GetStringUTF16(IDS_CROSTINI_LINUX));
} else if (is_plugin_vm_running) {
return l10n_util::GetStringFUTF16(
IDS_POLICY_DLP_CLIPBOARD_BLOCKED_ON_COPY_VM, host_name,
l10n_util::GetStringUTF16(IDS_PLUGIN_VM_APP_NAME));
} else {
NOTREACHED();
}
}
if (data_dst && data_dst->type() == ui::EndpointType::kArc) {
return l10n_util::GetStringFUTF16(
IDS_POLICY_DLP_CLIPBOARD_BLOCKED_ON_COPY_VM, host_name,
l10n_util::GetStringUTF16(IDS_POLICY_DLP_ANDROID_APPS));
}
return l10n_util::GetStringFUTF16(IDS_POLICY_DLP_CLIPBOARD_BLOCKED_ON_PASTE,
host_name);
}
} // namespace policy } // namespace policy
...@@ -6,6 +6,7 @@ ...@@ -6,6 +6,7 @@
#define CHROME_BROWSER_CHROMEOS_POLICY_DLP_DATA_TRANSFER_DLP_CONTROLLER_H_ #define CHROME_BROWSER_CHROMEOS_POLICY_DLP_DATA_TRANSFER_DLP_CONTROLLER_H_
#include "base/strings/string16.h" #include "base/strings/string16.h"
#include "chrome/browser/chromeos/policy/dlp/dlp_clipboard_notification_helper.h"
#include "ui/base/data_transfer_policy/data_transfer_policy_controller.h" #include "ui/base/data_transfer_policy/data_transfer_policy_controller.h"
namespace ui { namespace ui {
...@@ -28,24 +29,16 @@ class DataTransferDlpController : public ui::DataTransferPolicyController { ...@@ -28,24 +29,16 @@ class DataTransferDlpController : public ui::DataTransferPolicyController {
void operator=(const DataTransferDlpController&) = delete; void operator=(const DataTransferDlpController&) = delete;
// nullptr can be passed instead of `data_src` or `data_dst`. If data read is // nullptr can be passed instead of `data_src` or `data_dst`. If data read is
// not allowed, this function will show a toast to the user. // not allowed, this function will show a notification to the user.
bool IsDataReadAllowed( bool IsDataReadAllowed(
const ui::DataTransferEndpoint* const data_src, const ui::DataTransferEndpoint* const data_src,
const ui::DataTransferEndpoint* const data_dst) const override; const ui::DataTransferEndpoint* const data_dst) override;
private: private:
DataTransferDlpController(); DataTransferDlpController();
~DataTransferDlpController() override; ~DataTransferDlpController() override;
// Shows toast in case the data read is blocked. DlpClipboardNotificationHelper helper_;
// TODO(crbug.com/1131670): Move `ShowBlockToast` to a separate util/helper.
void ShowBlockToast(const base::string16& text) const;
// The text will be different if the data transferred is being shared with
// Crostini or Parallels or ARC.
base::string16 GetToastText(
const ui::DataTransferEndpoint* const data_src,
const ui::DataTransferEndpoint* const data_dst) const;
}; };
} // namespace policy } // namespace policy
......
// Copyright 2020 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/chromeos/policy/dlp/dlp_clipboard_notification_helper.h"
#include <memory>
#include <vector>
#include "ash/public/cpp/ash_features.h"
#include "ash/public/cpp/toast_data.h"
#include "ash/public/cpp/toast_manager.h"
#include "ash/public/cpp/window_tree_host_lookup.h"
#include "base/bind.h"
#include "base/strings/string16.h"
#include "base/strings/utf_string_conversions.h"
#include "base/time/time.h"
#include "chrome/browser/browser_process.h"
#include "chrome/browser/chromeos/crostini/crostini_util.h"
#include "chrome/browser/chromeos/plugin_vm/plugin_vm_util.h"
#include "chrome/browser/profiles/profile_manager.h"
#include "chrome/grit/generated_resources.h"
#include "components/strings/grit/components_strings.h"
#include "components/vector_icons/vector_icons.h"
#include "ui/aura/window_tree_host.h"
#include "ui/base/data_transfer_policy/data_transfer_endpoint.h"
#include "ui/base/ime/input_method.h"
#include "ui/base/ime/text_input_client.h"
#include "ui/base/l10n/l10n_util.h"
#include "ui/compositor/layer_owner.h"
#include "ui/compositor/scoped_layer_animation_settings.h"
#include "ui/display/display.h"
#include "ui/display/screen.h"
#include "ui/gfx/color_palette.h"
#include "ui/gfx/geometry/insets.h"
#include "ui/gfx/paint_vector_icon.h"
#include "ui/gfx/text_utils.h"
#include "ui/views/bubble/bubble_border.h"
#include "ui/views/controls/button/button.h"
#include "ui/views/controls/button/label_button.h"
#include "ui/views/controls/image_view.h"
#include "ui/views/view.h"
#include "ui/views/widget/widget.h"
namespace policy {
namespace {
// The name of the bubble.
constexpr char kBubbleName[] = "ClipboardDlpBubble";
// The corner radius of the bubble.
constexpr int kBubbleCornerRadius = 8;
constexpr gfx::RoundedCornersF kCornerRadii(kBubbleCornerRadius);
// The blur radius for the bubble background.
constexpr int kBubbleBlurRadius = 80;
// The alpha component of the bubble background.
constexpr float kBubbleBackgroundAlpha = 0.8f;
// The size of the managed icon.
constexpr int kManagedIconSize = 20;
// The maximum width of the label.
constexpr int kBubbleWidth = 360;
// The spacing between the icon and label in the bubble.
constexpr int kIconLabelSpacing = 16;
// The padding which separates the bubble border with its inner contents.
constexpr int kBubblePadding = 16;
// The line height of the bubble text.
constexpr int kLineHeight = 20;
// The insets of the bubble borders.
constexpr gfx::Insets kBubbleBorderInsets(1);
// Clipboard toast ID.
constexpr char kClipboardToastId[] = "clipboard_dlp_block";
// The duration of the clipboard toast.
constexpr int kToastDurationMs = 2500;
// The font of the text used in the bubble.
constexpr char kTextFont[] = "Roboto, 13px";
// The height of the dismiss button.
constexpr int kButtonHeight = 32;
// The padding which separates the button border with its inner contents.
constexpr int kButtonPadding = 16;
// The spacing between the button border and label.
constexpr int kButtonLabelSpacing = 8;
constexpr base::TimeDelta kBubbleBoundsAnimationTime =
base::TimeDelta::FromMilliseconds(250);
class DismissButton : public views::LabelButton {
public:
DismissButton() {
SetHorizontalAlignment(gfx::HorizontalAlignment::ALIGN_CENTER);
const base::string16 button_label(l10n_util::GetStringUTF16(
IDS_POLICY_DLP_CLIPBOARD_BLOCK_DISMISS_BUTTON));
SetText(button_label);
label()->SetFontList(gfx::FontList(kTextFont));
SetTextColor(ButtonState::STATE_NORMAL, gfx::kGoogleBlue800);
SetHorizontalAlignment(gfx::HorizontalAlignment::ALIGN_CENTER);
SetSize({gfx::GetStringWidth(button_label, gfx::FontList(kTextFont)) +
2 * kButtonPadding,
kButtonHeight});
}
int GetLabelWidth() { return label()->bounds().width(); }
DismissButton(const DismissButton&) = delete;
DismissButton& operator=(const DismissButton&) = delete;
~DismissButton() override = default;
};
// This inline bubble shown for disabled copy/paste.
class ClipboardBubbleView : public views::View {
public:
explicit ClipboardBubbleView(const base::string16& text) {
// TODO(crbug.com/1150740): Change colors in case of dark mode.
SetPaintToLayer(ui::LAYER_SOLID_COLOR);
layer()->SetColor(
SkColorSetA(SK_ColorWHITE, SK_AlphaOPAQUE * kBubbleBackgroundAlpha));
if (ash::features::IsBackgroundBlurEnabled())
layer()->SetBackgroundBlur(kBubbleBlurRadius);
layer()->SetRoundedCornerRadius(kCornerRadii);
// Add the managed icon.
SkColor icon_color = SK_ColorGRAY;
clipboard_icon_ = AddChildView(std::make_unique<views::ImageView>());
clipboard_icon_->SetPaintToLayer();
clipboard_icon_->layer()->SetFillsBoundsOpaquely(false);
clipboard_icon_->SetBounds(kBubblePadding, kBubblePadding, kManagedIconSize,
kManagedIconSize);
clipboard_icon_->SetImage(gfx::CreateVectorIcon(
vector_icons::kBusinessIcon, kManagedIconSize, icon_color));
// Add the bubble text.
label_ = AddChildView(std::make_unique<views::Label>());
label_->SetPaintToLayer();
label_->layer()->SetFillsBoundsOpaquely(false);
label_->SetPosition(gfx::Point(
kBubblePadding + kManagedIconSize + kIconLabelSpacing, kBubblePadding));
// Set the styling of the text.
// TODO(crbug.com/1150741): Handle RTL.
label_->SetText(text);
label_->SetFontList(gfx::FontList("Roboto, 13px"));
label_->SetEnabledColor(SK_ColorBLACK);
label_->SetLineHeight(kLineHeight);
label_->SetMultiLine(true);
label_->SizeToFit(kBubbleWidth - 2 * kBubblePadding - kManagedIconSize -
kIconLabelSpacing);
label_->SetHorizontalAlignment(gfx::HorizontalAlignment::ALIGN_LEFT);
// Bubble borders
border_ = AddChildView(std::make_unique<views::ImageView>());
border_->SetPaintToLayer();
border_->layer()->SetFillsBoundsOpaquely(false);
auto shadow_border = std::make_unique<views::BubbleBorder>(
views::BubbleBorder::FLOAT, views::BubbleBorder::SMALL_SHADOW,
SK_ColorTRANSPARENT);
shadow_border->SetCornerRadius(kBubbleCornerRadius);
shadow_border->set_background_color(SK_ColorTRANSPARENT);
shadow_border->set_insets(kBubbleBorderInsets);
border_->SetSize({kBubbleWidth, INT_MAX});
border_->SetBorder(std::move(shadow_border));
// Add "Got it" button.
button_ = AddChildView(std::make_unique<DismissButton>());
button_->SetPaintToLayer();
button_->layer()->SetFillsBoundsOpaquely(false);
button_->SetPosition(
gfx::Point(kBubbleWidth - kBubblePadding - button_->width(),
kBubblePadding + label_->height() + kButtonLabelSpacing));
}
~ClipboardBubbleView() override = default;
views::Label* label_ = nullptr;
views::ImageView* clipboard_icon_ = nullptr;
views::ImageView* border_ = nullptr;
DismissButton* button_ = nullptr;
};
bool IsRectContainedByAnyDisplay(const gfx::Rect& rect) {
const std::vector<display::Display>& displays =
display::Screen::GetScreen()->GetAllDisplays();
for (const auto& display : displays) {
if (display.bounds().Contains(rect))
return true;
}
return false;
}
void CalculateAndSetWidgetBounds(views::Widget* widget,
ClipboardBubbleView* bubble_view) {
display::Screen* screen = display::Screen::GetScreen();
display::Display display = screen->GetPrimaryDisplay();
auto* host = ash::GetWindowTreeHostForDisplay(display.id());
ui::TextInputClient* text_input_client =
host->GetInputMethod()->GetTextInputClient();
// `text_input_client` may be null. For example, in clamshell mode and without
// any window open.
if (!text_input_client)
return;
gfx::Rect caret_bounds = text_input_client->GetCaretBounds();
// Note that the width of caret's bounds may be zero in some views (such as
// the search bar of Google search web page). So we cannot use
// gfx::Size::IsEmpty() here. In addition, the applications using IFrame may
// provide unreliable `caret_bounds` which are not fully contained by the
// display bounds.
const bool caret_bounds_are_valid = caret_bounds.size() != gfx::Size() &&
IsRectContainedByAnyDisplay(caret_bounds);
if (!caret_bounds_are_valid) {
caret_bounds.set_origin(
display::Screen::GetScreen()->GetCursorScreenPoint());
}
// Calculate the bubble size to ensure the label text accurately fits.
const int bubble_height =
2 * kBubblePadding + bubble_view->label_->bounds().height() +
kButtonLabelSpacing + bubble_view->button_->height();
bubble_view->border_->SetSize({kBubbleWidth, bubble_height});
const gfx::Rect widget_bounds = gfx::Rect(caret_bounds.x(), caret_bounds.y(),
kBubbleWidth, bubble_height);
std::unique_ptr<ui::ScopedLayerAnimationSettings> settings;
if (widget->GetWindowBoundsInScreen().size() != gfx::Size()) {
settings = std::make_unique<ui::ScopedLayerAnimationSettings>(
widget->GetLayer()->GetAnimator());
settings->SetPreemptionStrategy(
ui::LayerAnimator::IMMEDIATELY_ANIMATE_TO_NEW_TARGET);
settings->SetTransitionDuration(kBubbleBoundsAnimationTime);
settings->SetTweenType(gfx::Tween::EASE_OUT);
}
widget->SetBounds(widget_bounds);
}
base::string16 GetGuestOsToastText(const base::string16& host_name) {
ProfileManager* profile_manager = g_browser_process->profile_manager();
Profile* profile =
profile_manager ? profile_manager->GetActiveUserProfile() : nullptr;
DCHECK(profile);
const bool is_crostini_running = crostini::IsCrostiniRunning(profile);
const bool is_plugin_vm_running = plugin_vm::IsPluginVmRunning(profile);
if (is_crostini_running && is_plugin_vm_running) {
return l10n_util::GetStringFUTF16(
IDS_POLICY_DLP_CLIPBOARD_BLOCKED_ON_COPY_TWO_VMS, host_name,
l10n_util::GetStringUTF16(IDS_CROSTINI_LINUX),
l10n_util::GetStringUTF16(IDS_PLUGIN_VM_APP_NAME));
}
if (is_crostini_running) {
return l10n_util::GetStringFUTF16(
IDS_POLICY_DLP_CLIPBOARD_BLOCKED_ON_COPY_VM, host_name,
l10n_util::GetStringUTF16(IDS_CROSTINI_LINUX));
}
if (is_plugin_vm_running) {
return l10n_util::GetStringFUTF16(
IDS_POLICY_DLP_CLIPBOARD_BLOCKED_ON_COPY_VM, host_name,
l10n_util::GetStringUTF16(IDS_PLUGIN_VM_APP_NAME));
}
NOTREACHED();
return base::string16();
}
} // namespace
void DlpClipboardNotificationHelper::NotifyBlockedPaste(
const ui::DataTransferEndpoint* const data_src,
const ui::DataTransferEndpoint* const data_dst) {
DCHECK(data_src);
DCHECK(data_src->origin());
const base::string16 host_name =
base::UTF8ToUTF16(data_src->origin()->host());
if (data_dst) {
if (data_dst->type() == ui::EndpointType::kGuestOs) {
ShowClipboardBlockToast(GetGuestOsToastText(host_name));
return;
}
if (data_dst->type() == ui::EndpointType::kArc) {
ShowClipboardBlockToast(l10n_util::GetStringFUTF16(
IDS_POLICY_DLP_CLIPBOARD_BLOCKED_ON_COPY_VM, host_name,
l10n_util::GetStringUTF16(IDS_POLICY_DLP_ANDROID_APPS)));
return;
}
}
ShowClipboardBlockBubble(l10n_util::GetStringFUTF16(
IDS_POLICY_DLP_CLIPBOARD_BLOCKED_ON_PASTE, host_name));
}
void DlpClipboardNotificationHelper::ShowClipboardBlockBubble(
const base::string16& text) {
widget_ = std::make_unique<views::Widget>();
views::Widget::InitParams params(
views::Widget::InitParams::TYPE_WINDOW_FRAMELESS);
params.z_order = ui::ZOrderLevel::kFloatingWindow;
params.activatable = views::Widget::InitParams::ACTIVATABLE_NO;
params.ownership = views::Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET;
params.name = kBubbleName;
params.layer_type = ui::LAYER_NOT_DRAWN;
params.parent = nullptr;
params.shadow_type = views::Widget::InitParams::ShadowType::kDrop;
widget_->Init(std::move(params));
auto* bubble_view =
widget_->SetContentsView(std::make_unique<ClipboardBubbleView>(text));
bubble_view->button_->SetCallback(
base::BindRepeating(&DlpClipboardNotificationHelper::OnWidgetClosing,
base::Unretained(this), widget_.get()));
CalculateAndSetWidgetBounds(widget_.get(), bubble_view);
widget_->Show();
base::ThreadTaskRunnerHandle::Get()->PostDelayedTask(
FROM_HERE,
base::BindOnce(&DlpClipboardNotificationHelper::OnWidgetClosing,
base::Unretained(this),
widget_.get()), // Safe as DlpClipboardNotificationHelper
// owns `widget_` and outlives it.
base::TimeDelta::FromMilliseconds(kToastDurationMs));
}
void DlpClipboardNotificationHelper::ShowClipboardBlockToast(
const base::string16& text) {
ash::ToastData toast(kClipboardToastId, text, kToastDurationMs,
/*dismiss_text=*/base::nullopt);
toast.is_managed = true;
ash::ToastManager::Get()->Show(toast);
}
void DlpClipboardNotificationHelper::OnWidgetClosing(views::Widget* widget) {
if (widget == widget_.get())
widget_.reset();
}
void DlpClipboardNotificationHelper::OnWidgetDestroyed(views::Widget* widget) {
if (widget == widget_.get())
widget_.reset();
}
} // namespace policy
// Copyright 2020 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_CHROMEOS_POLICY_DLP_DLP_CLIPBOARD_NOTIFICATION_HELPER_H_
#define CHROME_BROWSER_CHROMEOS_POLICY_DLP_DLP_CLIPBOARD_NOTIFICATION_HELPER_H_
#include "base/strings/string16.h"
#include "ui/base/data_transfer_policy/data_transfer_endpoint.h"
#include "ui/views/widget/unique_widget_ptr.h"
#include "ui/views/widget/widget.h"
#include "ui/views/widget/widget_observer.h"
namespace ui {
class DataTransferEndpoint;
}
namespace policy {
class DlpClipboardNotificationHelper : public views::WidgetObserver {
public:
DlpClipboardNotificationHelper() = default;
~DlpClipboardNotificationHelper() override = default;
DlpClipboardNotificationHelper(const DlpClipboardNotificationHelper&) =
delete;
void operator=(const DlpClipboardNotificationHelper&) = delete;
// Shows a bubble that clipboard paste is not allowed. If the type of
// `data_dst` is kGuestOS or kArc, it will show a toast instead of a
// notification.
void NotifyBlockedPaste(const ui::DataTransferEndpoint* const data_src,
const ui::DataTransferEndpoint* const data_dst);
private:
void ShowClipboardBlockBubble(const base::string16& text);
void ShowClipboardBlockToast(const base::string16& text);
// views::WidgetObserver
void OnWidgetClosing(views::Widget* widget) override;
void OnWidgetDestroyed(views::Widget* widget) override;
views::UniqueWidgetPtr widget_;
};
} // namespace policy
#endif // CHROME_BROWSER_CHROMEOS_POLICY_DLP_DLP_CLIPBOARD_NOTIFICATION_HELPER_H_
...@@ -780,7 +780,7 @@ class FakeDataTransferPolicyController ...@@ -780,7 +780,7 @@ class FakeDataTransferPolicyController
// ui::DataTransferPolicyController: // ui::DataTransferPolicyController:
bool IsDataReadAllowed( bool IsDataReadAllowed(
const ui::DataTransferEndpoint* const data_src, const ui::DataTransferEndpoint* const data_src,
const ui::DataTransferEndpoint* const data_dst) const override { const ui::DataTransferEndpoint* const data_dst) override {
// The multipaste menu should have access to any clipboard data. // The multipaste menu should have access to any clipboard data.
if (data_dst && data_dst->type() == ui::EndpointType::kClipboardHistory) if (data_dst && data_dst->type() == ui::EndpointType::kClipboardHistory)
return true; return true;
......
...@@ -585,6 +585,9 @@ Additional details: ...@@ -585,6 +585,9 @@ Additional details:
<message name="IDS_POLICY_DLP_ANDROID_APPS" desc="Name shown for ARC in data leak prevention toasts."> <message name="IDS_POLICY_DLP_ANDROID_APPS" desc="Name shown for ARC in data leak prevention toasts.">
Android apps Android apps
</message> </message>
<message name="IDS_POLICY_DLP_CLIPBOARD_BLOCK_DISMISS_BUTTON" desc="Dismiss dialog button label for disabled paste notification.">
Got it
</message>
<message name="IDS_POLICY_DLP_PRINTING_BLOCKED_TITLE" desc="The title for notification informing the user that printing is blocked."> <message name="IDS_POLICY_DLP_PRINTING_BLOCKED_TITLE" desc="The title for notification informing the user that printing is blocked.">
Printing is blocked Printing is blocked
</message> </message>
......
bde2dbb0124a0fb0b5782b260dfa77bdd7b7f7ce
\ No newline at end of file
...@@ -109,9 +109,9 @@ class MockPolicyController : public DataTransferPolicyController { ...@@ -109,9 +109,9 @@ class MockPolicyController : public DataTransferPolicyController {
MockPolicyController(); MockPolicyController();
~MockPolicyController() override; ~MockPolicyController() override;
MOCK_CONST_METHOD2(IsDataReadAllowed, MOCK_METHOD2(IsDataReadAllowed,
bool(const DataTransferEndpoint* const data_src, bool(const DataTransferEndpoint* const data_src,
const DataTransferEndpoint* const data_dst)); const DataTransferEndpoint* const data_dst));
}; };
MockPolicyController::MockPolicyController() = default; MockPolicyController::MockPolicyController() = default;
......
...@@ -29,7 +29,7 @@ class COMPONENT_EXPORT(UI_BASE_DATA_TRANSFER_POLICY) ...@@ -29,7 +29,7 @@ class COMPONENT_EXPORT(UI_BASE_DATA_TRANSFER_POLICY)
virtual bool IsDataReadAllowed( virtual bool IsDataReadAllowed(
const DataTransferEndpoint* const data_src, const DataTransferEndpoint* const data_src,
const DataTransferEndpoint* const data_dst) const = 0; const DataTransferEndpoint* const data_dst) = 0;
protected: protected:
DataTransferPolicyController(); DataTransferPolicyController();
......
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