Commit b26c69c1 authored by Aya ElAttar's avatar Aya ElAttar Committed by Chromium LUCI CQ

Changed notification helper to observe clipboard

- Changed notification helper to observe the
clipboard, and close the bubble if the clipboard
got changed.
- Refactored Bubble & Button classes to
base and derived classed, so it'd be easier
to support warning mode later.
- Moved some of the needed bubble constants
to a separate file.

Bug: 1167228
Change-Id: I103ef1c95e1036ba28d3c449ed801688d12d2868
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2632673Reviewed-by: default avatarSergey Poromov <poromov@chromium.org>
Commit-Queue: Aya Elsayed <ayaelattar@chromium.org>
Cr-Commit-Position: refs/heads/master@{#844518}
parent a9499454
...@@ -2258,6 +2258,7 @@ source_set("chromeos") { ...@@ -2258,6 +2258,7 @@ 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_bubble_constants.h",
"policy/dlp/dlp_clipboard_notification_helper.cc", "policy/dlp/dlp_clipboard_notification_helper.cc",
"policy/dlp/dlp_clipboard_notification_helper.h", "policy/dlp/dlp_clipboard_notification_helper.h",
"policy/dlp/dlp_content_manager.cc", "policy/dlp/dlp_content_manager.cc",
......
// 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.
#ifndef CHROME_BROWSER_CHROMEOS_POLICY_DLP_DLP_CLIPBOARD_BUBBLE_CONSTANTS_H_
#define CHROME_BROWSER_CHROMEOS_POLICY_DLP_DLP_CLIPBOARD_BUBBLE_CONSTANTS_H_
namespace policy {
// Clipboard ARC toast ID.
constexpr char kClipboardDlpArcToastId[] = "clipboard_dlp_block_arc";
// Clipboard Crostini toast ID.
constexpr char kClipboardDlpCrostiniToastId[] = "clipboard_dlp_block_crostini";
// Clipboard Plugin VM toast ID.
constexpr char kClipboardDlpPluginVmToastId[] = "clipboard_dlp_block_plugin_vm";
// The duration of the clipboard toast.
constexpr int kClipboardDlpToastDurationMs = 2500;
} // namespace policy
#endif // CHROME_BROWSER_CHROMEOS_POLICY_DLP_DLP_CLIPBOARD_BUBBLE_CONSTANTS_H_
...@@ -16,10 +16,12 @@ ...@@ -16,10 +16,12 @@
#include "base/strings/string16.h" #include "base/strings/string16.h"
#include "base/strings/utf_string_conversions.h" #include "base/strings/utf_string_conversions.h"
#include "base/time/time.h" #include "base/time/time.h"
#include "chrome/browser/chromeos/policy/dlp/dlp_clipboard_bubble_constants.h"
#include "chrome/grit/generated_resources.h" #include "chrome/grit/generated_resources.h"
#include "components/strings/grit/components_strings.h" #include "components/strings/grit/components_strings.h"
#include "components/vector_icons/vector_icons.h" #include "components/vector_icons/vector_icons.h"
#include "ui/aura/window_tree_host.h" #include "ui/aura/window_tree_host.h"
#include "ui/base/clipboard/clipboard_monitor.h"
#include "ui/base/data_transfer_policy/data_transfer_endpoint.h" #include "ui/base/data_transfer_policy/data_transfer_endpoint.h"
#include "ui/base/ime/input_method.h" #include "ui/base/ime/input_method.h"
#include "ui/base/ime/text_input_client.h" #include "ui/base/ime/text_input_client.h"
...@@ -31,6 +33,7 @@ ...@@ -31,6 +33,7 @@
#include "ui/gfx/color_palette.h" #include "ui/gfx/color_palette.h"
#include "ui/gfx/font_list.h" #include "ui/gfx/font_list.h"
#include "ui/gfx/geometry/insets.h" #include "ui/gfx/geometry/insets.h"
#include "ui/gfx/geometry/size.h"
#include "ui/gfx/paint_vector_icon.h" #include "ui/gfx/paint_vector_icon.h"
#include "ui/gfx/text_utils.h" #include "ui/gfx/text_utils.h"
#include "ui/views/bubble/bubble_border.h" #include "ui/views/bubble/bubble_border.h"
...@@ -72,18 +75,6 @@ constexpr int kLineHeight = 20; ...@@ -72,18 +75,6 @@ constexpr int kLineHeight = 20;
// The insets of the bubble borders. // The insets of the bubble borders.
constexpr gfx::Insets kBubbleBorderInsets(1); constexpr gfx::Insets kBubbleBorderInsets(1);
// Clipboard ARC toast ID.
constexpr char kClipboardArcToastId[] = "clipboard_dlp_block_arc";
// Clipboard Crostini toast ID.
constexpr char kClipboardCrostiniToastId[] = "clipboard_dlp_block_crostini";
// Clipboard Plugin VM toast ID.
constexpr char kClipboardPluginVmToastId[] = "clipboard_dlp_block_plugin_vm";
// The duration of the clipboard toast.
constexpr int kToastDurationMs = 2500;
// The font name of the text used in the bubble. // The font name of the text used in the bubble.
constexpr char kTextFontName[] = "Roboto"; constexpr char kTextFontName[] = "Roboto";
...@@ -102,13 +93,11 @@ constexpr int kButtonLabelSpacing = 8; ...@@ -102,13 +93,11 @@ constexpr int kButtonLabelSpacing = 8;
constexpr base::TimeDelta kBubbleBoundsAnimationTime = constexpr base::TimeDelta kBubbleBoundsAnimationTime =
base::TimeDelta::FromMilliseconds(250); base::TimeDelta::FromMilliseconds(250);
class DismissButton : public views::LabelButton { class Button : public views::LabelButton {
public: public:
DismissButton() { explicit Button(const base::string16& button_label) {
SetHorizontalAlignment(gfx::HorizontalAlignment::ALIGN_CENTER); SetHorizontalAlignment(gfx::HorizontalAlignment::ALIGN_CENTER);
const base::string16 button_label(l10n_util::GetStringUTF16(
IDS_POLICY_DLP_CLIPBOARD_BLOCK_DISMISS_BUTTON));
SetText(button_label); SetText(button_label);
const gfx::FontList font_list = GetFontList(); const gfx::FontList font_list = GetFontList();
...@@ -130,10 +119,10 @@ class DismissButton : public views::LabelButton { ...@@ -130,10 +119,10 @@ class DismissButton : public views::LabelButton {
gfx::Font::Weight::MEDIUM); gfx::Font::Weight::MEDIUM);
} }
DismissButton(const DismissButton&) = delete; Button(const Button&) = delete;
DismissButton& operator=(const DismissButton&) = delete; Button& operator=(const Button&) = delete;
~DismissButton() override = default; ~Button() override = default;
}; };
// This inline bubble shown for disabled copy/paste. // This inline bubble shown for disabled copy/paste.
...@@ -151,12 +140,12 @@ class ClipboardBubbleView : public views::View { ...@@ -151,12 +140,12 @@ class ClipboardBubbleView : public views::View {
// Add the managed icon. // Add the managed icon.
SkColor icon_color = color_provider->GetContentLayerColor( SkColor icon_color = color_provider->GetContentLayerColor(
ash::ColorProvider::ContentLayerType::kIconColorPrimary); ash::ColorProvider::ContentLayerType::kIconColorPrimary);
clipboard_icon_ = AddChildView(std::make_unique<views::ImageView>()); managed_icon_ = AddChildView(std::make_unique<views::ImageView>());
clipboard_icon_->SetPaintToLayer(); managed_icon_->SetPaintToLayer();
clipboard_icon_->layer()->SetFillsBoundsOpaquely(false); managed_icon_->layer()->SetFillsBoundsOpaquely(false);
clipboard_icon_->SetBounds(kBubblePadding, kBubblePadding, kManagedIconSize, managed_icon_->SetBounds(kBubblePadding, kBubblePadding, kManagedIconSize,
kManagedIconSize); kManagedIconSize);
clipboard_icon_->SetImage(gfx::CreateVectorIcon( managed_icon_->SetImage(gfx::CreateVectorIcon(
vector_icons::kBusinessIcon, kManagedIconSize, icon_color)); vector_icons::kBusinessIcon, kManagedIconSize, icon_color));
// Add the bubble text. // Add the bubble text.
...@@ -192,22 +181,54 @@ class ClipboardBubbleView : public views::View { ...@@ -192,22 +181,54 @@ class ClipboardBubbleView : public views::View {
shadow_border->set_insets(kBubbleBorderInsets); shadow_border->set_insets(kBubbleBorderInsets);
border_->SetSize({kBubbleWidth, INT_MAX}); border_->SetSize({kBubbleWidth, INT_MAX});
border_->SetBorder(std::move(shadow_border)); border_->SetBorder(std::move(shadow_border));
}
~ClipboardBubbleView() override = default;
virtual gfx::Size GetBubbleSize() = 0;
protected:
// This function should get called if the view got updated e.g. AddChildView.
void UpdateBorderSize(const gfx::Size& size) { border_->SetSize(size); }
views::Label* label_ = nullptr;
views::ImageView* managed_icon_ = nullptr;
views::ImageView* border_ = nullptr;
};
class ClipboardBlockBubble : public ClipboardBubbleView {
public:
explicit ClipboardBlockBubble(const base::string16& text)
: ClipboardBubbleView(text) {
// Add "Got it" button. // Add "Got it" button.
button_ = AddChildView(std::make_unique<DismissButton>()); base::string16 button_label = l10n_util::GetStringUTF16(
IDS_POLICY_DLP_CLIPBOARD_BLOCK_DISMISS_BUTTON);
button_ = AddChildView(std::make_unique<Button>(button_label));
button_->SetPaintToLayer(); button_->SetPaintToLayer();
button_->layer()->SetFillsBoundsOpaquely(false); button_->layer()->SetFillsBoundsOpaquely(false);
button_->SetPosition( button_->SetPosition(
gfx::Point(kBubbleWidth - kBubblePadding - button_->width(), gfx::Point(kBubbleWidth - kBubblePadding - button_->width(),
kBubblePadding + label_->height() + kButtonLabelSpacing)); kBubblePadding + label_->height() + kButtonLabelSpacing));
UpdateBorderSize(GetBubbleSize());
} }
~ClipboardBubbleView() override = default; ~ClipboardBlockBubble() override = default;
views::Label* label_ = nullptr; gfx::Size GetBubbleSize() override {
views::ImageView* clipboard_icon_ = nullptr; DCHECK(label_);
views::ImageView* border_ = nullptr; DCHECK(button_);
DismissButton* button_ = nullptr; return {kBubbleWidth, 2 * kBubblePadding + label_->bounds().height() +
kButtonLabelSpacing + button_->height()};
}
void SetDismissCallback(base::RepeatingCallback<void()> cb) {
DCHECK(button_);
button_->SetCallback(std::move(cb));
}
private:
Button* button_ = nullptr;
}; };
bool IsRectContainedByAnyDisplay(const gfx::Rect& rect) { bool IsRectContainedByAnyDisplay(const gfx::Rect& rect) {
...@@ -243,21 +264,16 @@ void CalculateAndSetWidgetBounds(views::Widget* widget, ...@@ -243,21 +264,16 @@ void CalculateAndSetWidgetBounds(views::Widget* widget,
// display bounds. // display bounds.
const bool caret_bounds_are_valid = caret_bounds.size() != gfx::Size() && const bool caret_bounds_are_valid = caret_bounds.size() != gfx::Size() &&
IsRectContainedByAnyDisplay(caret_bounds); IsRectContainedByAnyDisplay(caret_bounds);
if (!caret_bounds_are_valid) { if (!caret_bounds_are_valid) {
caret_bounds.set_origin( caret_bounds.set_origin(
display::Screen::GetScreen()->GetCursorScreenPoint()); display::Screen::GetScreen()->GetCursorScreenPoint());
} }
// Calculate the bubble size to ensure the label text accurately fits. // Calculate the bubble size to ensure the label text accurately fits.
const int bubble_height = const gfx::Size bubble_size = bubble_view->GetBubbleSize();
2 * kBubblePadding + bubble_view->label_->bounds().height() + const gfx::Rect widget_bounds =
kButtonLabelSpacing + bubble_view->button_->height(); gfx::Rect(caret_bounds.x(), caret_bounds.y(), bubble_size.width(),
bubble_size.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; std::unique_ptr<ui::ScopedLayerAnimationSettings> settings;
if (widget->GetWindowBoundsInScreen().size() != gfx::Size()) { if (widget->GetWindowBoundsInScreen().size() != gfx::Size()) {
...@@ -274,6 +290,14 @@ void CalculateAndSetWidgetBounds(views::Widget* widget, ...@@ -274,6 +290,14 @@ void CalculateAndSetWidgetBounds(views::Widget* widget,
} // namespace } // namespace
DlpClipboardNotificationHelper::DlpClipboardNotificationHelper() {
ui::ClipboardMonitor::GetInstance()->AddObserver(this);
}
DlpClipboardNotificationHelper::~DlpClipboardNotificationHelper() {
ui::ClipboardMonitor::GetInstance()->RemoveObserver(this);
}
void DlpClipboardNotificationHelper::NotifyBlockedPaste( void DlpClipboardNotificationHelper::NotifyBlockedPaste(
const ui::DataTransferEndpoint* const data_src, const ui::DataTransferEndpoint* const data_src,
const ui::DataTransferEndpoint* const data_dst) { const ui::DataTransferEndpoint* const data_dst) {
...@@ -285,7 +309,7 @@ void DlpClipboardNotificationHelper::NotifyBlockedPaste( ...@@ -285,7 +309,7 @@ void DlpClipboardNotificationHelper::NotifyBlockedPaste(
if (data_dst) { if (data_dst) {
if (data_dst->type() == ui::EndpointType::kCrostini) { if (data_dst->type() == ui::EndpointType::kCrostini) {
ShowClipboardBlockToast( ShowClipboardBlockToast(
kClipboardCrostiniToastId, kClipboardDlpCrostiniToastId,
l10n_util::GetStringFUTF16( l10n_util::GetStringFUTF16(
IDS_POLICY_DLP_CLIPBOARD_BLOCKED_ON_COPY_VM, host_name, IDS_POLICY_DLP_CLIPBOARD_BLOCKED_ON_COPY_VM, host_name,
l10n_util::GetStringUTF16(IDS_CROSTINI_LINUX))); l10n_util::GetStringUTF16(IDS_CROSTINI_LINUX)));
...@@ -293,7 +317,7 @@ void DlpClipboardNotificationHelper::NotifyBlockedPaste( ...@@ -293,7 +317,7 @@ void DlpClipboardNotificationHelper::NotifyBlockedPaste(
} }
if (data_dst->type() == ui::EndpointType::kPluginVm) { if (data_dst->type() == ui::EndpointType::kPluginVm) {
ShowClipboardBlockToast( ShowClipboardBlockToast(
kClipboardPluginVmToastId, kClipboardDlpPluginVmToastId,
l10n_util::GetStringFUTF16( l10n_util::GetStringFUTF16(
IDS_POLICY_DLP_CLIPBOARD_BLOCKED_ON_COPY_VM, host_name, IDS_POLICY_DLP_CLIPBOARD_BLOCKED_ON_COPY_VM, host_name,
l10n_util::GetStringUTF16(IDS_PLUGIN_VM_APP_NAME))); l10n_util::GetStringUTF16(IDS_PLUGIN_VM_APP_NAME)));
...@@ -301,7 +325,7 @@ void DlpClipboardNotificationHelper::NotifyBlockedPaste( ...@@ -301,7 +325,7 @@ void DlpClipboardNotificationHelper::NotifyBlockedPaste(
} }
if (data_dst->type() == ui::EndpointType::kArc) { if (data_dst->type() == ui::EndpointType::kArc) {
ShowClipboardBlockToast( ShowClipboardBlockToast(
kClipboardArcToastId, kClipboardDlpArcToastId,
l10n_util::GetStringFUTF16( l10n_util::GetStringFUTF16(
IDS_POLICY_DLP_CLIPBOARD_BLOCKED_ON_COPY_VM, host_name, IDS_POLICY_DLP_CLIPBOARD_BLOCKED_ON_COPY_VM, host_name,
l10n_util::GetStringUTF16(IDS_POLICY_DLP_ANDROID_APPS))); l10n_util::GetStringUTF16(IDS_POLICY_DLP_ANDROID_APPS)));
...@@ -327,14 +351,14 @@ void DlpClipboardNotificationHelper::ShowClipboardBlockBubble( ...@@ -327,14 +351,14 @@ void DlpClipboardNotificationHelper::ShowClipboardBlockBubble(
params.shadow_type = views::Widget::InitParams::ShadowType::kDrop; params.shadow_type = views::Widget::InitParams::ShadowType::kDrop;
widget_->Init(std::move(params)); widget_->Init(std::move(params));
auto* bubble_view = ClipboardBlockBubble* block_bubble =
widget_->SetContentsView(std::make_unique<ClipboardBubbleView>(text)); widget_->SetContentsView(std::make_unique<ClipboardBlockBubble>(text));
bubble_view->button_->SetCallback( block_bubble->SetDismissCallback(
base::BindRepeating(&DlpClipboardNotificationHelper::OnWidgetClosing, base::BindRepeating(&DlpClipboardNotificationHelper::OnWidgetClosing,
base::Unretained(this), widget_.get())); base::Unretained(this), widget_.get()));
CalculateAndSetWidgetBounds(widget_.get(), bubble_view); CalculateAndSetWidgetBounds(widget_.get(), block_bubble);
widget_->Show(); widget_->Show();
...@@ -344,13 +368,13 @@ void DlpClipboardNotificationHelper::ShowClipboardBlockBubble( ...@@ -344,13 +368,13 @@ void DlpClipboardNotificationHelper::ShowClipboardBlockBubble(
base::Unretained(this), base::Unretained(this),
widget_.get()), // Safe as DlpClipboardNotificationHelper widget_.get()), // Safe as DlpClipboardNotificationHelper
// owns `widget_` and outlives it. // owns `widget_` and outlives it.
base::TimeDelta::FromMilliseconds(kToastDurationMs)); base::TimeDelta::FromMilliseconds(kClipboardDlpToastDurationMs));
} }
void DlpClipboardNotificationHelper::ShowClipboardBlockToast( void DlpClipboardNotificationHelper::ShowClipboardBlockToast(
const std::string& id, const std::string& id,
const base::string16& text) { const base::string16& text) {
ash::ToastData toast(id, text, kToastDurationMs, ash::ToastData toast(id, text, kClipboardDlpToastDurationMs,
/*dismiss_text=*/base::nullopt); /*dismiss_text=*/base::nullopt);
toast.is_managed = true; toast.is_managed = true;
ash::ToastManager::Get()->Show(toast); ash::ToastManager::Get()->Show(toast);
...@@ -366,4 +390,8 @@ void DlpClipboardNotificationHelper::OnWidgetDestroyed(views::Widget* widget) { ...@@ -366,4 +390,8 @@ void DlpClipboardNotificationHelper::OnWidgetDestroyed(views::Widget* widget) {
widget_.reset(); widget_.reset();
} }
void DlpClipboardNotificationHelper::OnClipboardDataChanged() {
OnWidgetClosing(widget_.get());
}
} // namespace policy } // namespace policy
...@@ -6,6 +6,7 @@ ...@@ -6,6 +6,7 @@
#define 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 "base/strings/string16.h"
#include "ui/base/clipboard/clipboard_observer.h"
#include "ui/base/data_transfer_policy/data_transfer_endpoint.h" #include "ui/base/data_transfer_policy/data_transfer_endpoint.h"
#include "ui/views/widget/unique_widget_ptr.h" #include "ui/views/widget/unique_widget_ptr.h"
#include "ui/views/widget/widget.h" #include "ui/views/widget/widget.h"
...@@ -17,10 +18,11 @@ class DataTransferEndpoint; ...@@ -17,10 +18,11 @@ class DataTransferEndpoint;
namespace policy { namespace policy {
class DlpClipboardNotificationHelper : public views::WidgetObserver { class DlpClipboardNotificationHelper : public views::WidgetObserver,
public ui::ClipboardObserver {
public: public:
DlpClipboardNotificationHelper() = default; DlpClipboardNotificationHelper();
~DlpClipboardNotificationHelper() override = default; ~DlpClipboardNotificationHelper() override;
DlpClipboardNotificationHelper(const DlpClipboardNotificationHelper&) = DlpClipboardNotificationHelper(const DlpClipboardNotificationHelper&) =
delete; delete;
...@@ -41,6 +43,9 @@ class DlpClipboardNotificationHelper : public views::WidgetObserver { ...@@ -41,6 +43,9 @@ class DlpClipboardNotificationHelper : public views::WidgetObserver {
void OnWidgetClosing(views::Widget* widget) override; void OnWidgetClosing(views::Widget* widget) override;
void OnWidgetDestroyed(views::Widget* widget) override; void OnWidgetDestroyed(views::Widget* widget) override;
// ui::ClipboardObserver
void OnClipboardDataChanged() override;
views::UniqueWidgetPtr widget_; views::UniqueWidgetPtr widget_;
}; };
......
...@@ -9,6 +9,7 @@ ...@@ -9,6 +9,7 @@
#include "base/optional.h" #include "base/optional.h"
#include "base/stl_util.h" #include "base/stl_util.h"
#include "base/strings/utf_string_conversions.h" #include "base/strings/utf_string_conversions.h"
#include "chrome/browser/chromeos/policy/dlp/dlp_clipboard_bubble_constants.h"
#include "chrome/grit/generated_resources.h" #include "chrome/grit/generated_resources.h"
#include "components/strings/grit/components_strings.h" #include "components/strings/grit/components_strings.h"
#include "testing/gmock/include/gmock/gmock-matchers.h" #include "testing/gmock/include/gmock/gmock-matchers.h"
...@@ -105,13 +106,13 @@ INSTANTIATE_TEST_SUITE_P( ...@@ -105,13 +106,13 @@ INSTANTIATE_TEST_SUITE_P(
DlpClipboard, DlpClipboard,
DlpClipboardToastTest, DlpClipboardToastTest,
::testing::Values(ToastTest(ui::EndpointType::kCrostini, ::testing::Values(ToastTest(ui::EndpointType::kCrostini,
"clipboard_dlp_block_crostini", kClipboardDlpCrostiniToastId,
IDS_CROSTINI_LINUX), IDS_CROSTINI_LINUX),
ToastTest(ui::EndpointType::kPluginVm, ToastTest(ui::EndpointType::kPluginVm,
"clipboard_dlp_block_plugin_vm", kClipboardDlpPluginVmToastId,
IDS_PLUGIN_VM_APP_NAME), IDS_PLUGIN_VM_APP_NAME),
ToastTest(ui::EndpointType::kArc, ToastTest(ui::EndpointType::kArc,
"clipboard_dlp_block_arc", kClipboardDlpArcToastId,
IDS_POLICY_DLP_ANDROID_APPS))); IDS_POLICY_DLP_ANDROID_APPS)));
} // namespace policy } // namespace policy
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