Commit 69a66e6b authored by Keren Zhu's avatar Keren Zhu Committed by Commit Bot

Add IPH Snooze UI

* Add MdIPHBubbleButton, a transparent MD button with optional
white border.
* Add snoozable option to IPH bubble. Disable auto-dismiss for
snoozable button.

UX spec: https://docs.google.com/presentation/d/1l19RBFdJjsLIO2KPVANY-ObfwmUCkpQ1Lj8IeLAqJZM/edit#slide=id.g92aa3ae4f7_1_43
Screenshot: https://screenshot.googleplex.com/5brgyBvGcaoMeEP


Bug: 1121399
Change-Id: Ic3ca76b6edcb52bdc9d856aa6ee11476e018218d
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2394157Reviewed-by: default avatarWei Li <weili@chromium.org>
Reviewed-by: default avatarCollin Baker <collinbaker@chromium.org>
Commit-Queue: Keren Zhu <kerenzhu@chromium.org>
Cr-Commit-Position: refs/heads/master@{#805592}
parent 9c5516b0
...@@ -5889,6 +5889,12 @@ the Bookmarks menu."> ...@@ -5889,6 +5889,12 @@ the Bookmarks menu.">
<message name="IDS_TAB_GROUPS_NEW_GROUP_PROMO" desc="Text shown on promotional UI encouraging users to create a tab group in their tab strip"> <message name="IDS_TAB_GROUPS_NEW_GROUP_PROMO" desc="Text shown on promotional UI encouraging users to create a tab group in their tab strip">
To group tabs together, right-click a tab To group tabs together, right-click a tab
</message> </message>
<message name="IDS_PROMO_DISMISS_BUTTON" desc="Text shown on the button to dismiss a promotional UI">
Dismiss
</message>
<message name="IDS_PROMO_SNOOZE_BUTTON" desc="Text shown on the button to snooze a promotional UI, which indicates that users want to see this promotion at a later time">
Remind me later
</message>
<!-- Browser Hung Plugin Detector --> <!-- Browser Hung Plugin Detector -->
<if expr="is_win"> <if expr="is_win">
......
cec914674a8880399cb6e22ca7fa2f51ff131403
\ No newline at end of file
cec914674a8880399cb6e22ca7fa2f51ff131403
\ No newline at end of file
...@@ -9,6 +9,7 @@ ...@@ -9,6 +9,7 @@
#include "ui/base/default_style.h" #include "ui/base/default_style.h"
#include "ui/base/pointer/touch_ui_controller.h" #include "ui/base/pointer/touch_ui_controller.h"
#include "ui/base/resource/resource_bundle.h" #include "ui/base/resource/resource_bundle.h"
#include "ui/gfx/font.h"
#include "ui/gfx/platform_font.h" #include "ui/gfx/platform_font.h"
int GetFontSizeDeltaBoundedByAvailableHeight(int available_height, int GetFontSizeDeltaBoundedByAvailableHeight(int available_height,
...@@ -99,5 +100,9 @@ void ApplyCommonFontStyles(int context, ...@@ -99,5 +100,9 @@ void ApplyCommonFontStyles(int context,
*size_delta = 15 - gfx::PlatformFont::kDefaultBaseFontSize; *size_delta = 15 - gfx::PlatformFont::kDefaultBaseFontSize;
break; break;
#endif #endif
case CONTEXT_IPH_BUBBLE_BUTTON: {
*size_delta = GetFontSizeDeltaIgnoringUserOrLocaleSettings(12);
break;
}
} }
} }
...@@ -55,6 +55,9 @@ enum ChromeTextContext { ...@@ -55,6 +55,9 @@ enum ChromeTextContext {
// Status labels in the download shelf. Usually 10pt. // Status labels in the download shelf. Usually 10pt.
CONTEXT_DOWNLOAD_SHELF_STATUS, CONTEXT_DOWNLOAD_SHELF_STATUS,
// Button label in the IPH bubble.
CONTEXT_IPH_BUBBLE_BUTTON
}; };
enum ChromeTextStyle { enum ChromeTextStyle {
......
...@@ -63,6 +63,9 @@ struct FeaturePromoBubbleParams { ...@@ -63,6 +63,9 @@ struct FeaturePromoBubbleParams {
// Changes the bubble timeout. Intended for tests, avoid use. // Changes the bubble timeout. Intended for tests, avoid use.
base::Optional<base::TimeDelta> timeout_default; base::Optional<base::TimeDelta> timeout_default;
base::Optional<base::TimeDelta> timeout_short; base::Optional<base::TimeDelta> timeout_short;
// Determines if this IPH can be snoozed and reactivated later.
bool allow_snooze = false;
}; };
#endif // CHROME_BROWSER_UI_VIEWS_IN_PRODUCT_HELP_FEATURE_PROMO_BUBBLE_PARAMS_H_ #endif // CHROME_BROWSER_UI_VIEWS_IN_PRODUCT_HELP_FEATURE_PROMO_BUBBLE_PARAMS_H_
...@@ -11,19 +11,27 @@ ...@@ -11,19 +11,27 @@
#include "base/strings/string_number_conversions.h" #include "base/strings/string_number_conversions.h"
#include "chrome/browser/themes/theme_properties.h" #include "chrome/browser/themes/theme_properties.h"
#include "chrome/browser/ui/views/chrome_layout_provider.h" #include "chrome/browser/ui/views/chrome_layout_provider.h"
#include "chrome/browser/ui/views/chrome_typography.h"
#include "chrome/browser/ui/views/in_product_help/feature_promo_bubble_params.h" #include "chrome/browser/ui/views/in_product_help/feature_promo_bubble_params.h"
#include "chrome/browser/ui/views/in_product_help/feature_promo_bubble_timeout.h" #include "chrome/browser/ui/views/in_product_help/feature_promo_bubble_timeout.h"
#include "chrome/grit/generated_resources.h"
#include "components/variations/variations_associated_data.h" #include "components/variations/variations_associated_data.h"
#include "third_party/skia/include/core/SkColor.h"
#include "ui/base/l10n/l10n_util.h" #include "ui/base/l10n/l10n_util.h"
#include "ui/base/theme_provider.h" #include "ui/base/theme_provider.h"
#include "ui/gfx/geometry/insets.h" #include "ui/gfx/geometry/insets.h"
#include "ui/gfx/text_utils.h" #include "ui/gfx/text_utils.h"
#include "ui/views/accessibility/view_accessibility.h" #include "ui/views/accessibility/view_accessibility.h"
#include "ui/views/bubble/bubble_frame_view.h" #include "ui/views/bubble/bubble_frame_view.h"
#include "ui/views/controls/button/button.h"
#include "ui/views/controls/button/label_button.h"
#include "ui/views/controls/button/md_text_button.h"
#include "ui/views/controls/label.h" #include "ui/views/controls/label.h"
#include "ui/views/event_monitor.h" #include "ui/views/event_monitor.h"
#include "ui/views/layout/box_layout.h" #include "ui/views/layout/box_layout.h"
#include "ui/views/layout/fill_layout.h" #include "ui/views/layout/fill_layout.h"
#include "ui/views/layout/layout_provider.h"
#include "ui/views/view_class_properties.h"
namespace { namespace {
...@@ -38,19 +46,73 @@ constexpr base::TimeDelta kDelayShort = base::TimeDelta::FromSeconds(3); ...@@ -38,19 +46,73 @@ constexpr base::TimeDelta kDelayShort = base::TimeDelta::FromSeconds(3);
// The insets from the bubble border to the text inside. // The insets from the bubble border to the text inside.
constexpr gfx::Insets kBubbleContentsInsets(12, 16); constexpr gfx::Insets kBubbleContentsInsets(12, 16);
constexpr gfx::Insets kBubbleButtonPadding(10, 10);
} // namespace } // namespace
namespace views {
class MdIPHBubbleButton : public MdTextButton {
public:
MdIPHBubbleButton(ButtonListener* listener,
const base::string16& text,
bool has_border)
: MdTextButton(listener,
text,
ChromeTextContext::CONTEXT_IPH_BUBBLE_BUTTON),
has_border_(has_border) {
// Prominent style gives a button hover highlight.
SetProminent(true);
// Button color is the same as IPH bubble's color.
SetBgColorOverride(SK_ColorTRANSPARENT);
}
void UpdateBackgroundColor() override {
// Prominent MD button does not have a border.
// Override this method to draw a border.
// Adapted from MdTextButton::UpdateBackgroundColor()
ui::NativeTheme* theme = GetNativeTheme();
SkColor bg_color = SK_ColorTRANSPARENT;
if (GetState() == STATE_PRESSED)
theme->GetSystemButtonPressedColor(bg_color);
SkColor stroke_color =
has_border_
? theme->GetSystemColor(ui::NativeTheme::kColorId_ButtonBorderColor)
: SK_ColorTRANSPARENT;
SetBackground(CreateBackgroundFromPainter(
Painter::CreateRoundRectWith1PxBorderPainter(bg_color, stroke_color,
GetCornerRadius())));
}
private:
bool has_border_;
DISALLOW_COPY_AND_ASSIGN(MdIPHBubbleButton);
};
} // namespace views
FeaturePromoBubbleView::FeaturePromoBubbleView( FeaturePromoBubbleView::FeaturePromoBubbleView(
const FeaturePromoBubbleParams& params) const FeaturePromoBubbleParams& params,
base::RepeatingClosure snooze_callback,
base::RepeatingClosure dismiss_callback)
: BubbleDialogDelegateView(params.anchor_view, params.arrow), : BubbleDialogDelegateView(params.anchor_view, params.arrow),
snoozable_(params.allow_snooze),
activation_action_(params.activation_action), activation_action_(params.activation_action),
preferred_width_(params.preferred_width) { preferred_width_(params.preferred_width),
snooze_callback_(snooze_callback),
dismiss_callback_(dismiss_callback) {
DCHECK(params.anchor_view); DCHECK(params.anchor_view);
UseCompactMargins(); UseCompactMargins();
feature_promo_bubble_timeout_ = std::make_unique<FeaturePromoBubbleTimeout>( // Bubble will not auto-dismiss for snoozble IPH.
params.timeout_default ? *params.timeout_default : kDelayDefault, if (!snoozable_) {
params.timeout_short ? *params.timeout_short : kDelayShort); feature_promo_bubble_timeout_ = std::make_unique<FeaturePromoBubbleTimeout>(
params.timeout_default ? *params.timeout_default : kDelayDefault,
params.timeout_short ? *params.timeout_short : kDelayShort);
}
const base::string16 body_text = const base::string16 body_text =
l10n_util::GetStringUTF16(params.body_string_specifier); l10n_util::GetStringUTF16(params.body_string_specifier);
...@@ -75,15 +137,20 @@ FeaturePromoBubbleView::FeaturePromoBubbleView( ...@@ -75,15 +137,20 @@ FeaturePromoBubbleView::FeaturePromoBubbleView(
// created yet. // created yet.
const ui::ThemeProvider* theme_provider = const ui::ThemeProvider* theme_provider =
params.anchor_view->GetThemeProvider(); params.anchor_view->GetThemeProvider();
const views::LayoutProvider* layout_provider = views::LayoutProvider::Get();
DCHECK(theme_provider); DCHECK(theme_provider);
DCHECK(layout_provider);
const SkColor background_color = theme_provider->GetColor( const SkColor background_color = theme_provider->GetColor(
ThemeProperties::COLOR_FEATURE_PROMO_BUBBLE_BACKGROUND); ThemeProperties::COLOR_FEATURE_PROMO_BUBBLE_BACKGROUND);
const SkColor text_color = theme_provider->GetColor( const SkColor text_color = theme_provider->GetColor(
ThemeProperties::COLOR_FEATURE_PROMO_BUBBLE_TEXT); ThemeProperties::COLOR_FEATURE_PROMO_BUBBLE_TEXT);
const int vertical_spacing = layout_provider->GetDistanceMetric(
views::DISTANCE_UNRELATED_CONTROL_VERTICAL);
auto box_layout = std::make_unique<views::BoxLayout>( auto box_layout = std::make_unique<views::BoxLayout>(
views::BoxLayout::Orientation::kVertical, kBubbleContentsInsets, 0); views::BoxLayout::Orientation::kVertical, kBubbleContentsInsets,
vertical_spacing);
box_layout->set_main_axis_alignment( box_layout->set_main_axis_alignment(
views::BoxLayout::MainAxisAlignment::kCenter); views::BoxLayout::MainAxisAlignment::kCenter);
box_layout->set_cross_axis_alignment( box_layout->set_cross_axis_alignment(
...@@ -113,6 +180,34 @@ FeaturePromoBubbleView::FeaturePromoBubbleView( ...@@ -113,6 +180,34 @@ FeaturePromoBubbleView::FeaturePromoBubbleView(
body_label->SetHorizontalAlignment(gfx::ALIGN_LEFT); body_label->SetHorizontalAlignment(gfx::ALIGN_LEFT);
} }
if (snoozable_) {
auto* button_container = AddChildView(std::make_unique<views::View>());
auto* button_layout =
button_container->SetLayoutManager(std::make_unique<views::BoxLayout>(
views::BoxLayout::Orientation::kHorizontal));
button_layout->set_main_axis_alignment(
views::BoxLayout::MainAxisAlignment::kEnd);
const base::string16 skip_text =
l10n_util::GetStringUTF16(IDS_PROMO_DISMISS_BUTTON);
dismiss_button_ = button_container->AddChildView(
std::make_unique<views::MdIPHBubbleButton>(this, skip_text, false));
dismiss_button_->SetCustomPadding(kBubbleButtonPadding);
dismiss_button_->SetProperty(
views::kMarginsKey,
gfx::Insets(0, layout_provider->GetDistanceMetric(
views::DISTANCE_RELATED_BUTTON_HORIZONTAL)));
const base::string16 snooze_text =
l10n_util::GetStringUTF16(IDS_PROMO_SNOOZE_BUTTON);
snooze_button_ = button_container->AddChildView(
std::make_unique<views::MdIPHBubbleButton>(this, snooze_text, true));
snooze_button_->SetCustomPadding(kBubbleButtonPadding);
}
if (params.activation_action == if (params.activation_action ==
FeaturePromoBubbleParams::ActivationAction::DO_NOT_ACTIVATE) { FeaturePromoBubbleParams::ActivationAction::DO_NOT_ACTIVATE) {
SetCanActivate(false); SetCanActivate(false);
...@@ -131,15 +226,18 @@ FeaturePromoBubbleView::FeaturePromoBubbleView( ...@@ -131,15 +226,18 @@ FeaturePromoBubbleView::FeaturePromoBubbleView(
ChromeLayoutProvider::Get()->GetCornerRadiusMetric(views::EMPHASIS_HIGH)); ChromeLayoutProvider::Get()->GetCornerRadiusMetric(views::EMPHASIS_HIGH));
widget->Show(); widget->Show();
feature_promo_bubble_timeout_->OnBubbleShown(this); if (feature_promo_bubble_timeout_)
feature_promo_bubble_timeout_->OnBubbleShown(this);
} }
FeaturePromoBubbleView::~FeaturePromoBubbleView() = default; FeaturePromoBubbleView::~FeaturePromoBubbleView() = default;
// static // static
FeaturePromoBubbleView* FeaturePromoBubbleView::Create( FeaturePromoBubbleView* FeaturePromoBubbleView::Create(
const FeaturePromoBubbleParams& params) { const FeaturePromoBubbleParams& params,
return new FeaturePromoBubbleView(params); base::RepeatingClosure snooze_callback,
base::RepeatingClosure dismiss_callback) {
return new FeaturePromoBubbleView(params, snooze_callback, dismiss_callback);
} }
void FeaturePromoBubbleView::CloseBubble() { void FeaturePromoBubbleView::CloseBubble() {
...@@ -153,11 +251,22 @@ bool FeaturePromoBubbleView::OnMousePressed(const ui::MouseEvent& event) { ...@@ -153,11 +251,22 @@ bool FeaturePromoBubbleView::OnMousePressed(const ui::MouseEvent& event) {
} }
void FeaturePromoBubbleView::OnMouseEntered(const ui::MouseEvent& event) { void FeaturePromoBubbleView::OnMouseEntered(const ui::MouseEvent& event) {
feature_promo_bubble_timeout_->OnMouseEntered(); if (feature_promo_bubble_timeout_)
feature_promo_bubble_timeout_->OnMouseEntered();
} }
void FeaturePromoBubbleView::OnMouseExited(const ui::MouseEvent& event) { void FeaturePromoBubbleView::OnMouseExited(const ui::MouseEvent& event) {
feature_promo_bubble_timeout_->OnMouseExited(); if (feature_promo_bubble_timeout_)
feature_promo_bubble_timeout_->OnMouseExited();
}
void FeaturePromoBubbleView::ButtonPressed(views::Button* sender,
const ui::Event& event) {
CloseBubble();
if (sender == snooze_button_)
snooze_callback_.Run();
else // sender == dismiss_button_
dismiss_callback_.Run();
} }
gfx::Rect FeaturePromoBubbleView::GetBubbleBounds() { gfx::Rect FeaturePromoBubbleView::GetBubbleBounds() {
...@@ -190,3 +299,11 @@ gfx::Size FeaturePromoBubbleView::CalculatePreferredSize() const { ...@@ -190,3 +299,11 @@ gfx::Size FeaturePromoBubbleView::CalculatePreferredSize() const {
return View::CalculatePreferredSize(); return View::CalculatePreferredSize();
} }
} }
views::Button* FeaturePromoBubbleView::GetDismissButtonForTesting() const {
return dismiss_button_;
}
views::Button* FeaturePromoBubbleView::GetSnoozeButtonForTesting() const {
return snooze_button_;
}
...@@ -5,15 +5,16 @@ ...@@ -5,15 +5,16 @@
#ifndef CHROME_BROWSER_UI_VIEWS_IN_PRODUCT_HELP_FEATURE_PROMO_BUBBLE_VIEW_H_ #ifndef CHROME_BROWSER_UI_VIEWS_IN_PRODUCT_HELP_FEATURE_PROMO_BUBBLE_VIEW_H_
#define CHROME_BROWSER_UI_VIEWS_IN_PRODUCT_HELP_FEATURE_PROMO_BUBBLE_VIEW_H_ #define CHROME_BROWSER_UI_VIEWS_IN_PRODUCT_HELP_FEATURE_PROMO_BUBBLE_VIEW_H_
#include <cstddef>
#include <memory> #include <memory>
#include "base/macros.h"
#include "base/optional.h" #include "base/optional.h"
#include "base/timer/timer.h" #include "base/timer/timer.h"
#include "chrome/browser/ui/views/in_product_help/feature_promo_bubble_params.h" #include "chrome/browser/ui/views/in_product_help/feature_promo_bubble_params.h"
#include "chrome/browser/ui/views/in_product_help/feature_promo_bubble_timeout.h" #include "chrome/browser/ui/views/in_product_help/feature_promo_bubble_timeout.h"
#include "ui/gfx/geometry/rect.h" #include "ui/gfx/geometry/rect.h"
#include "ui/views/bubble/bubble_dialog_delegate_view.h" #include "ui/views/bubble/bubble_dialog_delegate_view.h"
#include "ui/views/controls/button/button.h"
namespace gfx { namespace gfx {
class Rect; class Rect;
...@@ -23,22 +24,38 @@ namespace ui { ...@@ -23,22 +24,38 @@ namespace ui {
class MouseEvent; class MouseEvent;
} // namespace ui } // namespace ui
namespace views {
class MdTextButton;
}
// The FeaturePromoBubbleView is a special BubbleDialogDelegateView for // The FeaturePromoBubbleView is a special BubbleDialogDelegateView for
// in-product help which educates users about certain Chrome features in a // in-product help which educates users about certain Chrome features in a
// deferred context. // deferred context.
class FeaturePromoBubbleView : public views::BubbleDialogDelegateView { class FeaturePromoBubbleView : public views::BubbleDialogDelegateView,
public views::ButtonListener {
public: public:
// Disallow copy and assign.
FeaturePromoBubbleView(const FeaturePromoBubbleView&) = delete;
FeaturePromoBubbleView& operator=(const FeaturePromoBubbleView&) = delete;
~FeaturePromoBubbleView() override; ~FeaturePromoBubbleView() override;
// Creates the promo. The returned pointer is only valid until the // Creates the promo. The returned pointer is only valid until the
// widget is destroyed. It must not be manually deleted by the caller. // widget is destroyed. It must not be manually deleted by the caller.
static FeaturePromoBubbleView* Create(const FeaturePromoBubbleParams& params); static FeaturePromoBubbleView* Create(
const FeaturePromoBubbleParams& params,
base::RepeatingClosure snooze_callback = base::RepeatingClosure(),
base::RepeatingClosure dismiss_callback = base::RepeatingClosure());
// Closes the promo bubble. // Closes the promo bubble.
void CloseBubble(); void CloseBubble();
views::Button* GetDismissButtonForTesting() const;
views::Button* GetSnoozeButtonForTesting() const;
private: private:
explicit FeaturePromoBubbleView(const FeaturePromoBubbleParams& params); FeaturePromoBubbleView(const FeaturePromoBubbleParams& params,
base::RepeatingClosure snooze_callback,
base::RepeatingClosure dismiss_callback);
// BubbleDialogDelegateView: // BubbleDialogDelegateView:
bool OnMousePressed(const ui::MouseEvent& event) override; bool OnMousePressed(const ui::MouseEvent& event) override;
...@@ -52,6 +69,15 @@ class FeaturePromoBubbleView : public views::BubbleDialogDelegateView { ...@@ -52,6 +69,15 @@ class FeaturePromoBubbleView : public views::BubbleDialogDelegateView {
} }
gfx::Size CalculatePreferredSize() const override; gfx::Size CalculatePreferredSize() const override;
// ButtonListener:
void ButtonPressed(views::Button* sender, const ui::Event& event) override;
// Determines if this bubble has dismiss and snooze buttons.
bool snoozable_;
views::MdTextButton* dismiss_button_ = nullptr;
views::MdTextButton* snooze_button_ = nullptr;
const FeaturePromoBubbleParams::ActivationAction activation_action_; const FeaturePromoBubbleParams::ActivationAction activation_action_;
base::string16 accessible_name_; base::string16 accessible_name_;
...@@ -60,7 +86,8 @@ class FeaturePromoBubbleView : public views::BubbleDialogDelegateView { ...@@ -60,7 +86,8 @@ class FeaturePromoBubbleView : public views::BubbleDialogDelegateView {
std::unique_ptr<FeaturePromoBubbleTimeout> feature_promo_bubble_timeout_; std::unique_ptr<FeaturePromoBubbleTimeout> feature_promo_bubble_timeout_;
DISALLOW_COPY_AND_ASSIGN(FeaturePromoBubbleView); base::RepeatingClosure snooze_callback_;
base::RepeatingClosure dismiss_callback_;
}; };
#endif // CHROME_BROWSER_UI_VIEWS_IN_PRODUCT_HELP_FEATURE_PROMO_BUBBLE_VIEW_H_ #endif // CHROME_BROWSER_UI_VIEWS_IN_PRODUCT_HELP_FEATURE_PROMO_BUBBLE_VIEW_H_
// 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/ui/views/in_product_help/feature_promo_bubble_view.h"
#include <memory>
#include "base/bind.h"
#include "base/callback_forward.h"
#include "base/test/task_environment.h"
#include "chrome/browser/ui/views/frame/browser_view.h"
#include "chrome/browser/ui/views/frame/test_with_browser_view.h"
#include "chrome/browser/ui/views/in_product_help/feature_promo_bubble_params.h"
#include "chrome/grit/generated_resources.h"
#include "chrome/test/chromedriver/chrome/ui_events.h"
#include "testing/gmock/include/gmock/gmock.h"
#include "ui/events/base_event_utils.h"
#include "ui/events/event.h"
#include "ui/events/types/event_type.h"
#include "ui/views/widget/widget_observer.h"
class FeaturePromoBubbleDelegate {
public:
virtual void OnDismiss() = 0;
virtual void OnSnooze() = 0;
};
class MockFeaturePromoBubbleDelegate : public FeaturePromoBubbleDelegate {
public:
MOCK_METHOD(void, OnDismiss, (), ());
MOCK_METHOD(void, OnSnooze, (), ());
};
class FeaturePromoBubbleViewTest : public TestWithBrowserView {
public:
FeaturePromoBubbleViewTest()
: TestWithBrowserView(
base::test::SingleThreadTaskEnvironment::TimeSource::MOCK_TIME) {}
protected:
FeaturePromoBubbleParams GetBubbleParams(bool snoozable) {
FeaturePromoBubbleParams params;
params.body_string_specifier = IDS_REOPEN_TAB_PROMO;
params.anchor_view = browser_view()->contents_container();
params.arrow = views::BubbleBorder::TOP_RIGHT;
params.allow_snooze = snoozable;
return params;
}
};
class MockWidgetObserver : public views::WidgetObserver {
public:
MOCK_METHOD(void, OnWidgetClosing, (views::Widget*), ());
};
TEST_F(FeaturePromoBubbleViewTest, CallDismiss) {
MockFeaturePromoBubbleDelegate callback;
EXPECT_CALL(callback, OnDismiss()).Times(1);
FeaturePromoBubbleView* bubble = FeaturePromoBubbleView::Create(
GetBubbleParams(true), base::RepeatingClosure(),
base::BindRepeating(&FeaturePromoBubbleDelegate::OnDismiss,
base::Unretained(&callback)));
// Simulate clicks on dismiss button.
ui::MouseEvent mouse_press(ui::ET_MOUSE_PRESSED, gfx::Point(), gfx::Point(),
ui::EventTimeForNow(), ui::EF_LEFT_MOUSE_BUTTON,
ui::EF_LEFT_MOUSE_BUTTON);
ui::MouseEvent mouse_release(
ui::ET_MOUSE_RELEASED, gfx::Point(), gfx::Point(), ui::EventTimeForNow(),
ui::EF_LEFT_MOUSE_BUTTON, ui::EF_LEFT_MOUSE_BUTTON);
bubble->GetDismissButtonForTesting()->OnMouseEvent(&mouse_press);
bubble->GetDismissButtonForTesting()->OnMouseEvent(&mouse_release);
bubble->GetWidget()->Close();
}
TEST_F(FeaturePromoBubbleViewTest, CallSnooze) {
MockFeaturePromoBubbleDelegate callback;
EXPECT_CALL(callback, OnSnooze()).Times(1);
FeaturePromoBubbleView* bubble = FeaturePromoBubbleView::Create(
GetBubbleParams(true),
base::BindRepeating(&FeaturePromoBubbleDelegate::OnSnooze,
base::Unretained(&callback)));
// Simulate clicks on snooze button.
ui::MouseEvent mouse_press(ui::ET_MOUSE_PRESSED, gfx::Point(), gfx::Point(),
ui::EventTimeForNow(), ui::EF_LEFT_MOUSE_BUTTON,
ui::EF_LEFT_MOUSE_BUTTON);
ui::MouseEvent mouse_release(
ui::ET_MOUSE_RELEASED, gfx::Point(), gfx::Point(), ui::EventTimeForNow(),
ui::EF_LEFT_MOUSE_BUTTON, ui::EF_LEFT_MOUSE_BUTTON);
bubble->GetSnoozeButtonForTesting()->OnMouseEvent(&mouse_press);
bubble->GetSnoozeButtonForTesting()->OnMouseEvent(&mouse_release);
bubble->GetWidget()->Close();
}
TEST_F(FeaturePromoBubbleViewTest, NoButtonIfNotSnoozable) {
FeaturePromoBubbleView* bubble =
FeaturePromoBubbleView::Create(GetBubbleParams(false));
EXPECT_FALSE(bubble->GetSnoozeButtonForTesting());
EXPECT_FALSE(bubble->GetDismissButtonForTesting());
bubble->GetWidget()->Close();
}
TEST_F(FeaturePromoBubbleViewTest, AutoDismissIfNotSnoozable) {
FeaturePromoBubbleView* bubble =
FeaturePromoBubbleView::Create(GetBubbleParams(false));
MockWidgetObserver dismiss_observer;
EXPECT_CALL(dismiss_observer, OnWidgetClosing(testing::_)).Times(1);
bubble->GetWidget()->AddObserver(&dismiss_observer);
task_environment()->FastForwardBy(base::TimeDelta::FromMinutes(1));
task_environment()->RunUntilIdle();
}
TEST_F(FeaturePromoBubbleViewTest, NoAutoDismissIfSnoozable) {
FeaturePromoBubbleView* bubble =
FeaturePromoBubbleView::Create(GetBubbleParams(true));
MockWidgetObserver dismiss_observer;
EXPECT_CALL(dismiss_observer, OnWidgetClosing(testing::_)).Times(0);
bubble->GetWidget()->AddObserver(&dismiss_observer);
task_environment()->FastForwardBy(base::TimeDelta::FromMinutes(1));
task_environment()->RunUntilIdle();
// WidgetObserver checks if it is in an observer list in its destructor.
// Need to remove it from widget manually.
bubble->GetWidget()->RemoveObserver(&dismiss_observer);
}
...@@ -5666,6 +5666,7 @@ test("unit_tests") { ...@@ -5666,6 +5666,7 @@ test("unit_tests") {
"../browser/ui/views/global_media_controls/media_notification_list_view_unittest.cc", "../browser/ui/views/global_media_controls/media_notification_list_view_unittest.cc",
"../browser/ui/views/global_media_controls/overlay_media_notification_view_unittest.cc", "../browser/ui/views/global_media_controls/overlay_media_notification_view_unittest.cc",
"../browser/ui/views/hover_button_unittest.cc", "../browser/ui/views/hover_button_unittest.cc",
"../browser/ui/views/in_product_help/feature_promo_bubble_view_unittest.cc",
"../browser/ui/views/in_product_help/feature_promo_controller_views_unittest.cc", "../browser/ui/views/in_product_help/feature_promo_controller_views_unittest.cc",
"../browser/ui/views/infobars/infobar_view_unittest.cc", "../browser/ui/views/infobars/infobar_view_unittest.cc",
"../browser/ui/views/intent_picker_bubble_view_unittest.cc", "../browser/ui/views/intent_picker_bubble_view_unittest.cc",
......
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