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

DLP: Clipboard warning bubble

- Added the required strings for the clipboard
warning bubble.
- Created the warning bubble which should be
shown before paste.

Bug: 1167228
Change-Id: If4563426fff95ab74722e41283c7184b2a6929c2
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2637639
Commit-Queue: Aya Elsayed <ayaelattar@chromium.org>
Reviewed-by: default avatarSergey Poromov <poromov@chromium.org>
Cr-Commit-Position: refs/heads/master@{#846023}
parent be4e3200
......@@ -16,8 +16,11 @@ 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;
// The duration of the clipboard toast/bubble shown on blocked paste.
constexpr int kClipboardDlpBlockDurationMs = 2500;
// The duration of the clipboard warning shown before paste.
constexpr int kClipboardDlpWarnDurationMs = 20000;
} // namespace policy
......
......@@ -60,7 +60,7 @@ constexpr int kBubbleBlurRadius = 80;
// The size of the managed icon.
constexpr int kManagedIconSize = 20;
// The maximum width of the label.
// The maximum width of the bubble.
constexpr int kBubbleWidth = 360;
// The spacing between the icon and label in the bubble.
......@@ -90,6 +90,9 @@ constexpr int kButtonPadding = 16;
// The spacing between the button border and label.
constexpr int kButtonLabelSpacing = 8;
// The spacing between the buttons.
constexpr int kButtonsSpacing = 8;
constexpr base::TimeDelta kBubbleBoundsAnimationTime =
base::TimeDelta::FromMilliseconds(250);
......@@ -231,6 +234,59 @@ class ClipboardBlockBubble : public ClipboardBubbleView {
Button* button_ = nullptr;
};
class ClipboardWarnBubble : public ClipboardBubbleView {
public:
explicit ClipboardWarnBubble(const base::string16& text)
: ClipboardBubbleView(text) {
// Add paste button.
base::string16 paste_label =
l10n_util::GetStringUTF16(IDS_POLICY_DLP_CLIPBOARD_WARN_PROCEED_BUTTON);
paste_button_ = AddChildView(std::make_unique<Button>(paste_label));
paste_button_->SetPaintToLayer();
paste_button_->layer()->SetFillsBoundsOpaquely(false);
paste_button_->SetPosition(
gfx::Point(kBubbleWidth - kBubblePadding - paste_button_->width(),
kBubblePadding + label_->height() + kButtonLabelSpacing));
// Add cancel button.
base::string16 cancel_label =
l10n_util::GetStringUTF16(IDS_POLICY_DLP_CLIPBOARD_WARN_DISMISS_BUTTON);
cancel_button_ = AddChildView(std::make_unique<Button>(cancel_label));
cancel_button_->SetPaintToLayer();
cancel_button_->layer()->SetFillsBoundsOpaquely(false);
cancel_button_->SetPosition(
gfx::Point(kBubbleWidth - kBubblePadding - paste_button_->width() -
kButtonsSpacing - cancel_button_->width(),
kBubblePadding + label_->height() + kButtonLabelSpacing));
UpdateBorderSize(GetBubbleSize());
}
~ClipboardWarnBubble() override = default;
gfx::Size GetBubbleSize() override {
DCHECK(label_);
DCHECK(cancel_button_);
DCHECK(paste_button_);
return {kBubbleWidth, 2 * kBubblePadding + label_->bounds().height() +
kButtonLabelSpacing + paste_button_->height()};
}
void SetDismissCallback(base::RepeatingCallback<void()> cb) {
DCHECK(cancel_button_);
cancel_button_->SetCallback(std::move(cb));
}
void SetProceedCallback(base::RepeatingCallback<void()> cb) {
DCHECK(paste_button_);
// TODO(crbug.com/1168106): Add the logic for "paste".
}
private:
Button* cancel_button_ = nullptr;
Button* paste_button_ = nullptr;
};
bool IsRectContainedByAnyDisplay(const gfx::Rect& rect) {
const std::vector<display::Display>& displays =
display::Screen::GetScreen()->GetAllDisplays();
......@@ -242,7 +298,7 @@ bool IsRectContainedByAnyDisplay(const gfx::Rect& rect) {
}
void CalculateAndSetWidgetBounds(views::Widget* widget,
ClipboardBubbleView* bubble_view) {
const gfx::Size& bubble_size) {
display::Screen* screen = display::Screen::GetScreen();
display::Display display = screen->GetPrimaryDisplay();
auto* host = ash::GetWindowTreeHostForDisplay(display.id());
......@@ -269,8 +325,6 @@ void CalculateAndSetWidgetBounds(views::Widget* widget,
display::Screen::GetScreen()->GetCursorScreenPoint());
}
// Calculate the bubble size to ensure the label text accurately fits.
const gfx::Size bubble_size = bubble_view->GetBubbleSize();
const gfx::Rect widget_bounds =
gfx::Rect(caret_bounds.x(), caret_bounds.y(), bubble_size.width(),
bubble_size.height());
......@@ -288,6 +342,19 @@ void CalculateAndSetWidgetBounds(views::Widget* widget,
widget->SetBounds(widget_bounds);
}
views::Widget::InitParams GetWidgetInitParams() {
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;
return params;
}
} // namespace
DlpClipboardNotificationHelper::DlpClipboardNotificationHelper() {
......@@ -336,21 +403,37 @@ void DlpClipboardNotificationHelper::NotifyBlockedPaste(
IDS_POLICY_DLP_CLIPBOARD_BLOCKED_ON_PASTE, host_name));
}
void DlpClipboardNotificationHelper::WarnOnPaste(
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::kCrostini) {
// TODO(crbug.com/1168104): Support toasts in warning mode.
return;
}
if (data_dst->type() == ui::EndpointType::kPluginVm) {
// TODO(crbug.com/1168104): Support toasts in warning mode.
return;
}
if (data_dst->type() == ui::EndpointType::kArc) {
// TODO(crbug.com/1168104): Support toasts in warning mode.
return;
}
}
ShowClipboardWarnBubble(l10n_util::GetStringFUTF16(
IDS_POLICY_DLP_CLIPBOARD_WARN_ON_PASTE, host_name));
}
void DlpClipboardNotificationHelper::ShowClipboardBlockBubble(
const base::string16& text) {
widget_ = std::make_unique<views::Widget>();
widget_->Init(GetWidgetInitParams());
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));
ClipboardBlockBubble* block_bubble =
widget_->SetContentsView(std::make_unique<ClipboardBlockBubble>(text));
......@@ -358,28 +441,36 @@ void DlpClipboardNotificationHelper::ShowClipboardBlockBubble(
base::BindRepeating(&DlpClipboardNotificationHelper::OnWidgetClosing,
base::Unretained(this), widget_.get()));
CalculateAndSetWidgetBounds(widget_.get(), block_bubble);
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(kClipboardDlpToastDurationMs));
ResizeAndShowWidget(block_bubble->GetBubbleSize(),
kClipboardDlpBlockDurationMs);
}
void DlpClipboardNotificationHelper::ShowClipboardBlockToast(
const std::string& id,
const base::string16& text) {
ash::ToastData toast(id, text, kClipboardDlpToastDurationMs,
ash::ToastData toast(id, text, kClipboardDlpBlockDurationMs,
/*dismiss_text=*/base::nullopt);
toast.is_managed = true;
ash::ToastManager::Get()->Show(toast);
}
void DlpClipboardNotificationHelper::ShowClipboardWarnBubble(
const base::string16& text) {
widget_ = std::make_unique<views::Widget>();
widget_->Init(GetWidgetInitParams());
ClipboardWarnBubble* warn_bubble =
widget_->SetContentsView(std::make_unique<ClipboardWarnBubble>(text));
warn_bubble->SetDismissCallback(
base::BindRepeating(&DlpClipboardNotificationHelper::OnWidgetClosing,
base::Unretained(this), widget_.get()));
// TODO(crbug.com/1168106): Set proceed callback.
ResizeAndShowWidget(warn_bubble->GetBubbleSize(),
kClipboardDlpWarnDurationMs);
}
void DlpClipboardNotificationHelper::OnWidgetClosing(views::Widget* widget) {
if (widget == widget_.get())
widget_.reset();
......@@ -394,4 +485,22 @@ void DlpClipboardNotificationHelper::OnClipboardDataChanged() {
OnWidgetClosing(widget_.get());
}
void DlpClipboardNotificationHelper::ResizeAndShowWidget(
const gfx::Size& bubble_size,
int timeout_duration_ms) {
DCHECK(widget_);
CalculateAndSetWidgetBounds(widget_.get(), bubble_size);
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(timeout_duration_ms));
}
} // namespace policy
......@@ -29,15 +29,21 @@ class DlpClipboardNotificationHelper : public views::WidgetObserver,
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.
// `data_dst` is kCrostini, kPluginVm 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);
// Shows a bubble that warns the user that clipboard paste is not recommended.
// If the type of `data_dst` is kCrostini, kPluginVm or kArc, it will show a
// toast instead of a notification.
void WarnOnPaste(const ui::DataTransferEndpoint* const data_src,
const ui::DataTransferEndpoint* const data_dst);
private:
virtual void ShowClipboardBlockBubble(const base::string16& text);
virtual void ShowClipboardBlockToast(const std::string& id,
const base::string16& text);
virtual void ShowClipboardWarnBubble(const base::string16& text);
// views::WidgetObserver
void OnWidgetClosing(views::Widget* widget) override;
......@@ -46,6 +52,9 @@ class DlpClipboardNotificationHelper : public views::WidgetObserver,
// ui::ClipboardObserver
void OnClipboardDataChanged() override;
void ResizeAndShowWidget(const gfx::Size& bubble_size,
int timeout_duration_ms);
views::UniqueWidgetPtr widget_;
};
......
......@@ -603,6 +603,15 @@ Additional details:
<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_CLIPBOARD_WARN_ON_PASTE" desc="A toast informing the user that paste is blocked.">
Pasting from <ph name="ORIGIN_NAME">$1<ex>corp.google.com</ex></ph> to this location is not recommended by administrator policy
</message>
<message name="IDS_POLICY_DLP_CLIPBOARD_WARN_PROCEED_BUTTON" desc="Proceed dialog button label for warning before paste.">
Paste anyway
</message>
<message name="IDS_POLICY_DLP_CLIPBOARD_WARN_DISMISS_BUTTON" desc="Dismiss dialog button label for warning before paste.">
Cancel
</message>
<message name="IDS_POLICY_DLP_PRINTING_BLOCKED_TITLE" desc="The title for notification informing the user that printing is blocked.">
Printing is blocked
</message>
......
4a680838ea9d33190623dc1fb4ffb8c63810ec28
\ No newline at end of file
4a680838ea9d33190623dc1fb4ffb8c63810ec28
\ No newline at end of file
4a680838ea9d33190623dc1fb4ffb8c63810ec28
\ No newline at end of file
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