diff options
author | Allan Sandfeld Jensen <allan.jensen@qt.io> | 2019-07-31 15:50:41 +0200 |
---|---|---|
committer | Allan Sandfeld Jensen <allan.jensen@qt.io> | 2019-08-30 12:35:23 +0000 |
commit | 7b2ffa587235a47d4094787d72f38102089f402a (patch) | |
tree | 30e82af9cbab08a7fa028bb18f4f2987a3f74dfa /chromium/ui/message_center | |
parent | d94af01c90575348c4e81a418257f254b6f8d225 (diff) | |
download | qtwebengine-chromium-7b2ffa587235a47d4094787d72f38102089f402a.tar.gz |
BASELINE: Update Chromium to 76.0.3809.94
Change-Id: I321c3f5f929c105aec0f98c5091ef6108822e647
Reviewed-by: Michael BrĂ¼ning <michael.bruning@qt.io>
Diffstat (limited to 'chromium/ui/message_center')
33 files changed, 280 insertions, 2832 deletions
diff --git a/chromium/ui/message_center/BUILD.gn b/chromium/ui/message_center/BUILD.gn index 010d522389b..cf5163b7908 100644 --- a/chromium/ui/message_center/BUILD.gn +++ b/chromium/ui/message_center/BUILD.gn @@ -92,8 +92,6 @@ jumbo_component("message_center") { if (toolkit_views) { sources += [ - "views/bounded_label.cc", - "views/bounded_label.h", "views/desktop_popup_alignment_delegate.cc", "views/desktop_popup_alignment_delegate.h", "views/message_popup_collection.cc", @@ -126,16 +124,6 @@ jumbo_component("message_center") { "views/slide_out_controller.cc", "views/slide_out_controller.h", ] - if (!is_chromeos) { - sources += [ - "views/message_view_context_menu_controller.cc", - "views/message_view_context_menu_controller.h", - "views/notification_menu_model.cc", - "views/notification_menu_model.h", - "views/notification_view.cc", - "views/notification_view.h", - ] - } deps += [ "//ui/compositor", "//ui/events", @@ -223,23 +211,13 @@ if (enable_message_center) { if (toolkit_views) { sources += [ - "views/bounded_label_unittest.cc", "views/message_popup_collection_unittest.cc", "views/notification_header_view_unittest.cc", "views/notification_view_md_unittest.cc", "views/relative_time_formatter_unittest.cc", "views/slide_out_controller_unittest.cc", ] - if (!is_chromeos) { - sources += [ - "views/notification_menu_model_unittest.cc", - "views/notification_view_unittest.cc", - ] - } deps += [ - # Compositor is needed by message_center_view_unittest.cc and for the - # fonts used by bounded_label_unittest.cc. - "//ui/compositor", "//ui/display", "//ui/strings", "//ui/views", diff --git a/chromium/ui/message_center/public/cpp/BUILD.gn b/chromium/ui/message_center/public/cpp/BUILD.gn index a647bb534f5..6dc7ee3b7af 100644 --- a/chromium/ui/message_center/public/cpp/BUILD.gn +++ b/chromium/ui/message_center/public/cpp/BUILD.gn @@ -9,8 +9,6 @@ jumbo_component("cpp") { output_name = "ui_message_center_cpp" sources = [ - "features.cc", - "features.h", "message_center_constants.h", "message_center_public_export.h", "notification.cc", diff --git a/chromium/ui/message_center/public/cpp/features.cc b/chromium/ui/message_center/public/cpp/features.cc deleted file mode 100644 index 3b923d0e996..00000000000 --- a/chromium/ui/message_center/public/cpp/features.cc +++ /dev/null @@ -1,12 +0,0 @@ -// Copyright 2014 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 "ui/message_center/public/cpp/features.h" - -namespace message_center { - -const base::Feature kNewStyleNotifications{"NewStyleNotifications", - base::FEATURE_ENABLED_BY_DEFAULT}; - -} // namespace message_center diff --git a/chromium/ui/message_center/public/cpp/features.h b/chromium/ui/message_center/public/cpp/features.h deleted file mode 100644 index dadaddbb22e..00000000000 --- a/chromium/ui/message_center/public/cpp/features.h +++ /dev/null @@ -1,19 +0,0 @@ -// Copyright 2018 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 UI_MESSAGE_CENTER_PUBLIC_CPP_FEATURES_H_ -#define UI_MESSAGE_CENTER_PUBLIC_CPP_FEATURES_H_ - -#include "base/feature_list.h" -#include "ui/message_center/public/cpp/message_center_public_export.h" - -namespace message_center { - -// This feature controls whether the new (material design) style notifications -// should be used. -MESSAGE_CENTER_PUBLIC_EXPORT extern const base::Feature kNewStyleNotifications; - -} // namespace message_center - -#endif // UI_MESSAGE_CENTER_PUBLIC_CPP_FEATURES_H_ diff --git a/chromium/ui/message_center/public/cpp/notification.cc b/chromium/ui/message_center/public/cpp/notification.cc index 25fe154b736..1f58c7ffe48 100644 --- a/chromium/ui/message_center/public/cpp/notification.cc +++ b/chromium/ui/message_center/public/cpp/notification.cc @@ -35,12 +35,10 @@ const gfx::ImageSkia CreateSolidColorImage(int width, return gfx::ImageSkia::CreateFrom1xBitmap(bitmap); } -gfx::Image DeepCopyImage(const gfx::Image& image) { - if (image.IsEmpty()) - return gfx::Image(); - std::unique_ptr<gfx::ImageSkia> image_skia( - new gfx::ImageSkia(*image.ToImageSkia())); - return gfx::Image(*image_skia); +// Returns an image created on the current thread that shares the same +// underlying ImageSkia data as the original image. +gfx::Image DuplicateImage(const gfx::Image& image) { + return image.IsEmpty() ? gfx::Image() : gfx::Image(image.AsImageSkia()); } } // namespace @@ -105,16 +103,16 @@ std::unique_ptr<Notification> Notification::DeepCopy( bool include_icon_images) { std::unique_ptr<Notification> notification_copy = std::make_unique<Notification>(notification); - notification_copy->set_icon(DeepCopyImage(notification_copy->icon())); + notification_copy->set_icon(DuplicateImage(notification_copy->icon())); notification_copy->set_image(include_body_image - ? DeepCopyImage(notification_copy->image()) + ? DuplicateImage(notification_copy->image()) : gfx::Image()); notification_copy->set_small_image( include_small_image ? notification_copy->small_image() : gfx::Image()); for (size_t i = 0; i < notification_copy->buttons().size(); i++) { notification_copy->SetButtonIcon( i, include_icon_images - ? DeepCopyImage(notification_copy->buttons()[i].icon) + ? DuplicateImage(notification_copy->buttons()[i].icon) : gfx::Image()); } return notification_copy; diff --git a/chromium/ui/message_center/views/bounded_label.cc b/chromium/ui/message_center/views/bounded_label.cc deleted file mode 100644 index 9e3d2e502c3..00000000000 --- a/chromium/ui/message_center/views/bounded_label.cc +++ /dev/null @@ -1,379 +0,0 @@ -// Copyright 2013 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 "ui/message_center/views/bounded_label.h" - -#include <stddef.h> - -#include <limits> - -#include "base/macros.h" -#include "base/strings/string_util.h" -#include "base/strings/utf_string_conversions.h" -#include "ui/gfx/canvas.h" -#include "ui/gfx/text_elider.h" -#include "ui/gfx/text_utils.h" -#include "ui/views/controls/label.h" - -namespace { - -const size_t kPreferredLinesCacheSize = 10; - -} // namespace - -namespace message_center { - -// InnerBoundedLabel /////////////////////////////////////////////////////////// - -// InnerBoundedLabel is a views::Label subclass that does all of the work for -// BoundedLabel. It is kept private to prevent outside code from calling a -// number of views::Label methods like SetFontList() that break BoundedLabel's -// caching but can't be overridden. -// -// TODO(dharcourt): Move the line limiting functionality to views::Label to make -// this unnecessary. - -class InnerBoundedLabel : public views::Label { - public: - InnerBoundedLabel(const BoundedLabel& owner); - ~InnerBoundedLabel() override; - - void SetNativeTheme(const ui::NativeTheme* theme); - - // Pass in a -1 width to use the preferred width, a -1 limit to skip limits. - int GetLinesForWidthAndLimit(int width, int limit); - gfx::Size GetSizeForWidthAndLines(int width, int lines); - std::vector<base::string16> GetWrappedText(int width, int lines); - - // Overridden from views::Label. - void SetText(const base::string16& new_text) override; - void OnPaint(gfx::Canvas* canvas) override; - - protected: - // Overridden from views::Label. - void OnBoundsChanged(const gfx::Rect& previous_bounds) override; - - private: - int GetTextFlags(); - - void ClearCaches(); - int GetCachedLines(int width); - void SetCachedLines(int width, int lines); - gfx::Size GetCachedSize(const std::pair<int, int>& width_and_lines); - void SetCachedSize(std::pair<int, int> width_and_lines, gfx::Size size); - - const BoundedLabel* owner_; // Weak reference. - base::string16 wrapped_text_; - int wrapped_text_width_; - int wrapped_text_lines_; - std::map<int, int> lines_cache_; - std::list<int> lines_widths_; // Most recently used in front. - std::map<std::pair<int, int>, gfx::Size> size_cache_; - std::list<std::pair<int, int> > size_widths_and_lines_; // Recent in front. - - DISALLOW_COPY_AND_ASSIGN(InnerBoundedLabel); -}; - -InnerBoundedLabel::InnerBoundedLabel(const BoundedLabel& owner) - : owner_(&owner), - wrapped_text_width_(0), - wrapped_text_lines_(0) { - SetMultiLine(true); - SetAllowCharacterBreak(true); - SetHorizontalAlignment(gfx::ALIGN_LEFT); - set_collapse_when_hidden(true); -} - -InnerBoundedLabel::~InnerBoundedLabel() { -} - -void InnerBoundedLabel::SetNativeTheme(const ui::NativeTheme* theme) { - ClearCaches(); - OnNativeThemeChanged(theme); -} - -int InnerBoundedLabel::GetLinesForWidthAndLimit(int width, int limit) { - if (width == 0 || limit == 0) - return 0; - int lines = GetCachedLines(width); - if (lines == std::numeric_limits<int>::max()) { - int text_width = std::max(width - owner_->GetInsets().width(), 0); - lines = GetWrappedText(text_width, lines).size(); - SetCachedLines(width, lines); - } - return (limit < 0 || lines <= limit) ? lines : limit; -} - -gfx::Size InnerBoundedLabel::GetSizeForWidthAndLines(int width, int lines) { - if (width == 0 || lines == 0) - return gfx::Size(); - std::pair<int, int> key(width, lines); - gfx::Size size = GetCachedSize(key); - if (size.height() == std::numeric_limits<int>::max()) { - gfx::Insets insets = owner_->GetInsets(); - int text_width = (width < 0) ? std::numeric_limits<int>::max() : - std::max(width - insets.width(), 0); - int text_height = std::numeric_limits<int>::max(); - std::vector<base::string16> wrapped = GetWrappedText(text_width, lines); - gfx::Canvas::SizeStringInt( - base::JoinString(wrapped, base::ASCIIToUTF16("\n")), - font_list(), &text_width, &text_height, owner_->GetLineHeight(), - GetTextFlags()); - size.set_width(text_width + insets.width()); - size.set_height(text_height + insets.height()); - SetCachedSize(key, size); - } - return size; -} - -std::vector<base::string16> InnerBoundedLabel::GetWrappedText(int width, - int lines) { - // Short circuit simple case. - if (width == 0 || lines == 0) - return std::vector<base::string16>(); - - // Restrict line limit to ensure (lines + 1) * line_height <= INT_MAX and - // use it to calculate a reasonable text height. - int height = std::numeric_limits<int>::max(); - if (lines > 0) { - int line_height = std::max(font_list().GetHeight(), - 2); // At least 2 pixels. - int max_lines = std::numeric_limits<int>::max() / line_height - 1; - lines = std::min(lines, max_lines); - height = (lines + 1) * line_height; - } - - // Wrap, using INT_MAX for -1 widths that indicate no wrapping. - std::vector<base::string16> wrapped; - gfx::ElideRectangleText(text(), font_list(), - (width < 0) ? std::numeric_limits<int>::max() : width, - height, gfx::WRAP_LONG_WORDS, &wrapped); - - // Elide if necessary. - if (lines > 0 && wrapped.size() > static_cast<unsigned int>(lines)) { - // Add an ellipsis to the last line. If this ellipsis makes the last line - // too wide, that line will be further elided by the gfx::ElideText below, - // so for example "ABC" could become "ABC..." and then "AB...". - base::string16 last = - wrapped[lines - 1] + base::UTF8ToUTF16(gfx::kEllipsis); - if (width > 0 && gfx::GetStringWidth(last, font_list()) > width) - last = gfx::ElideText(last, font_list(), width, gfx::ELIDE_TAIL); - wrapped.resize(lines - 1); - wrapped.push_back(last); - } - - return wrapped; -} - -void InnerBoundedLabel::OnBoundsChanged(const gfx::Rect& previous_bounds) { - ClearCaches(); - views::Label::OnBoundsChanged(previous_bounds); -} - -void InnerBoundedLabel::OnPaint(gfx::Canvas* canvas) { - views::Label::OnPaintBackground(canvas); - views::Label::OnPaintBorder(canvas); - int lines = owner_->GetLineLimit(); - int height = GetSizeForWidthAndLines(width(), lines).height(); - if (height > 0) { - gfx::Rect bounds(width(), height); - bounds.Inset(owner_->GetInsets()); - if (bounds.width() != wrapped_text_width_ || lines != wrapped_text_lines_) { - wrapped_text_ = base::JoinString(GetWrappedText(bounds.width(), lines), - base::ASCIIToUTF16("\n")); - wrapped_text_width_ = bounds.width(); - wrapped_text_lines_ = lines; - } - bounds.set_x(GetMirroredXForRect(bounds)); - canvas->DrawStringRectWithFlags( - wrapped_text_, font_list(), enabled_color(), bounds, GetTextFlags()); - } -} - -void InnerBoundedLabel::SetText(const base::string16& new_text) { - if (text() == new_text) - return; - views::Label::SetText(new_text); - ClearCaches(); -} - -int InnerBoundedLabel::GetTextFlags() { - int flags = gfx::Canvas::MULTI_LINE | gfx::Canvas::CHARACTER_BREAKABLE; - - // We can't use subpixel rendering if the background is non-opaque. - if (SkColorGetA(background_color()) != 0xFF) - flags |= gfx::Canvas::NO_SUBPIXEL_RENDERING; - - return flags | gfx::Canvas::TEXT_ALIGN_TO_HEAD; -} - -void InnerBoundedLabel::ClearCaches() { - wrapped_text_width_ = 0; - wrapped_text_lines_ = 0; - lines_cache_.clear(); - lines_widths_.clear(); - size_cache_.clear(); - size_widths_and_lines_.clear(); -} - -int InnerBoundedLabel::GetCachedLines(int width) { - int lines = std::numeric_limits<int>::max(); - std::map<int, int>::const_iterator found; - if ((found = lines_cache_.find(width)) != lines_cache_.end()) { - lines = found->second; - lines_widths_.remove(width); - lines_widths_.push_front(width); - } - return lines; -} - -void InnerBoundedLabel::SetCachedLines(int width, int lines) { - if (lines_cache_.size() >= kPreferredLinesCacheSize) { - lines_cache_.erase(lines_widths_.back()); - lines_widths_.pop_back(); - } - lines_cache_[width] = lines; - lines_widths_.push_front(width); -} - -gfx::Size InnerBoundedLabel::GetCachedSize( - const std::pair<int, int>& width_and_lines) { - gfx::Size size(width_and_lines.first, std::numeric_limits<int>::max()); - std::map<std::pair<int, int>, gfx::Size>::const_iterator found; - if ((found = size_cache_.find(width_and_lines)) != size_cache_.end()) { - size = found->second; - size_widths_and_lines_.remove(width_and_lines); - size_widths_and_lines_.push_front(width_and_lines); - } - return size; -} - -void InnerBoundedLabel::SetCachedSize(std::pair<int, int> width_and_lines, - gfx::Size size) { - if (size_cache_.size() >= kPreferredLinesCacheSize) { - size_cache_.erase(size_widths_and_lines_.back()); - size_widths_and_lines_.pop_back(); - } - size_cache_[width_and_lines] = size; - size_widths_and_lines_.push_front(width_and_lines); -} - -// BoundedLabel /////////////////////////////////////////////////////////// - -BoundedLabel::BoundedLabel(const base::string16& text, - const gfx::FontList& font_list) - : line_limit_(-1), fixed_width_(0) { - label_.reset(new InnerBoundedLabel(*this)); - label_->SetFontList(font_list); - label_->SetText(text); -} - -BoundedLabel::BoundedLabel(const base::string16& text) - : line_limit_(-1), fixed_width_(0) { - label_.reset(new InnerBoundedLabel(*this)); - label_->SetText(text); -} - -BoundedLabel::~BoundedLabel() { -} - -void BoundedLabel::SetColor(SkColor text_color) { - label_->SetEnabledColor(text_color); - label_->SetAutoColorReadabilityEnabled(false); -} - -void BoundedLabel::SetLineHeight(int height) { - label_->SetLineHeight(height); -} - -void BoundedLabel::SetLineLimit(int lines) { - line_limit_ = std::max(lines, -1); -} - -void BoundedLabel::SetText(const base::string16& text) { - label_->SetText(text); -} - -int BoundedLabel::GetLineHeight() const { - return label_->line_height(); -} - -int BoundedLabel::GetLineLimit() const { - return line_limit_; -} - -const gfx::FontList& BoundedLabel::font_list() const { - return label_->font_list(); -} - -int BoundedLabel::GetLinesForWidthAndLimit(int width, int limit) { - return visible() ? label_->GetLinesForWidthAndLimit(width, limit) : 0; -} - -gfx::Size BoundedLabel::GetSizeForWidthAndLines(int width, int lines) { - return visible() ? - label_->GetSizeForWidthAndLines(width, lines) : gfx::Size(); -} - -void BoundedLabel::SizeToFit(int fixed_width) { - fixed_width_ = fixed_width; - label_->SizeToFit(fixed_width); -} - -int BoundedLabel::GetBaseline() const { - return label_->GetBaseline(); -} - -gfx::Size BoundedLabel::CalculatePreferredSize() const { - if (!visible()) - return gfx::Size(); - return fixed_width_ != 0 - ? label_->GetSizeForWidthAndLines(fixed_width_, line_limit_) - : label_->GetSizeForWidthAndLines(-1, -1); -} - -int BoundedLabel::GetHeightForWidth(int width) const { - return visible() ? - label_->GetSizeForWidthAndLines(width, line_limit_).height() : 0; -} - -void BoundedLabel::OnPaint(gfx::Canvas* canvas) { - label_->OnPaint(canvas); -} - -bool BoundedLabel::CanProcessEventsWithinSubtree() const { - return label_->CanProcessEventsWithinSubtree(); -} - -void BoundedLabel::GetAccessibleNodeData(ui::AXNodeData* node_data) { - label_->GetAccessibleNodeData(node_data); -} - -views::View* BoundedLabel::GetTooltipHandlerForPoint(const gfx::Point& point) { - if (GetSizeForWidthAndLines(width(), -1).height() <= - GetHeightForWidth(width())) { - return nullptr; - } - return HitTestPoint(point) ? this : nullptr; -} - -base::string16 BoundedLabel::GetTooltipText(const gfx::Point& p) const { - return label_->GetTooltipText(p); -} - -void BoundedLabel::OnBoundsChanged(const gfx::Rect& previous_bounds) { - label_->SetBoundsRect(bounds()); - views::View::OnBoundsChanged(previous_bounds); -} - -void BoundedLabel::OnNativeThemeChanged(const ui::NativeTheme* theme) { - label_->SetNativeTheme(theme); -} - -base::string16 BoundedLabel::GetWrappedTextForTest(int width, int lines) { - return base::JoinString(label_->GetWrappedText(width, lines), - base::ASCIIToUTF16("\n")); -} - -} // namespace message_center diff --git a/chromium/ui/message_center/views/bounded_label.h b/chromium/ui/message_center/views/bounded_label.h deleted file mode 100644 index 9e25e39a6c5..00000000000 --- a/chromium/ui/message_center/views/bounded_label.h +++ /dev/null @@ -1,86 +0,0 @@ -// Copyright 2013 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 UI_MESSAGE_CENTER_BOUNDED_LABEL_H_ -#define UI_MESSAGE_CENTER_BOUNDED_LABEL_H_ - -#include <list> -#include <map> -#include <memory> - -#include "base/macros.h" -#include "third_party/skia/include/core/SkColor.h" -#include "ui/message_center/message_center_export.h" -#include "ui/views/view.h" - -namespace gfx { -class FontList; -} - -namespace message_center { - -class InnerBoundedLabel; - -namespace test { -class BoundedLabelTest; -} - -// BoundedLabels display left aligned text up to a maximum number of lines, with -// ellipsis at the end of the last line for any omitted text. BoundedLabel is a -// direct subclass of views::Views rather than a subclass of views::Label -// to avoid exposing some of views::Label's methods that can't be made to work -// with BoundedLabel. See the description of InnerBoundedLabel in the -// bounded_label.cc file for details. -class MESSAGE_CENTER_EXPORT BoundedLabel : public views::View { - public: - BoundedLabel(const base::string16& text, const gfx::FontList& font_list); - BoundedLabel(const base::string16& text); - ~BoundedLabel() override; - - void SetColor(SkColor text_color); - void SetLineHeight(int height); // Pass in 0 for default height. - void SetLineLimit(int lines); // Pass in -1 for no limit. - void SetText(const base::string16& text); // Additionally clears caches. - void SizeToFit(int fixed_width); // Same interface as Label::SizeToFit. - - int GetLineHeight() const; - int GetLineLimit() const; - - // Gets the FontList used by this label. - const gfx::FontList& font_list() const; - - // Pass in a -1 width to use the preferred width, a -1 limit to skip limits. - int GetLinesForWidthAndLimit(int width, int limit); - gfx::Size GetSizeForWidthAndLines(int width, int lines); - - // views::View: - int GetBaseline() const override; - gfx::Size CalculatePreferredSize() const override; - int GetHeightForWidth(int width) const override; - void OnPaint(gfx::Canvas* canvas) override; - bool CanProcessEventsWithinSubtree() const override; - void GetAccessibleNodeData(ui::AXNodeData* node_data) override; - views::View* GetTooltipHandlerForPoint(const gfx::Point& point) override; - base::string16 GetTooltipText(const gfx::Point& p) const override; - - protected: - // Overridden from views::View. - void OnBoundsChanged(const gfx::Rect& previous_bounds) override; - void OnNativeThemeChanged(const ui::NativeTheme* theme) override; - - private: - friend class test::BoundedLabelTest; - - base::string16 GetWrappedTextForTest(int width, int lines); - - std::unique_ptr<InnerBoundedLabel> label_; - int line_limit_; - int fixed_width_; - - DISALLOW_COPY_AND_ASSIGN(BoundedLabel); -}; - -} // namespace message_center - -#endif // UI_MESSAGE_CENTER_BOUNDED_LABEL_H_ diff --git a/chromium/ui/message_center/views/bounded_label_unittest.cc b/chromium/ui/message_center/views/bounded_label_unittest.cc deleted file mode 100644 index 45e45608111..00000000000 --- a/chromium/ui/message_center/views/bounded_label_unittest.cc +++ /dev/null @@ -1,231 +0,0 @@ -// Copyright 2013 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 "ui/message_center/views/bounded_label.h" - -#include <limits> - -#include "base/strings/string_util.h" -#include "base/strings/utf_string_conversions.h" -#include "build/build_config.h" -#include "testing/gtest/include/gtest/gtest.h" -#include "ui/gfx/font_list.h" -#include "ui/gfx/text_utils.h" -#include "ui/views/controls/label.h" -#include "ui/views/test/views_test_base.h" - -#if defined(OS_MACOSX) -#include "base/mac/mac_util.h" -#endif - -namespace message_center { - -namespace test { - -/* Test fixture ***************************************************************/ - -class BoundedLabelTest : public views::ViewsTestBase { - public: - BoundedLabelTest() { - digit_pixels_ = gfx::GetStringWidthF(base::UTF8ToUTF16("0"), font_list_); - space_pixels_ = gfx::GetStringWidthF(base::UTF8ToUTF16(" "), font_list_); - ellipsis_pixels_ = - gfx::GetStringWidthF(base::UTF8ToUTF16("\xE2\x80\xA6"), font_list_); - } - - ~BoundedLabelTest() override {} - - // Replaces all occurences of three periods ("...") in the specified string - // with an ellipses character (UTF8 "\xE2\x80\xA6") and returns a string16 - // with the results. This allows test strings to be specified as ASCII const - // char* strings, making tests more readable and easier to write. - base::string16 ToString(const char* string) { - const char kPeriods[] = "..."; - const char kEllipses[] = "\xE2\x80\xA6"; - std::string result = string; - base::ReplaceSubstringsAfterOffset(&result, 0, kPeriods, kEllipses); - return base::UTF8ToUTF16(result); - } - - // Converts the specified elision width to pixels. To make tests somewhat - // independent of the fonts of the platform on which they're run, the elision - // widths are specified as XYZ integers, with the corresponding width in - // pixels being X times the width of digit characters plus Y times the width - // of spaces plus Z times the width of ellipses in the default font of the - // test plaform. It is assumed that all digits have the same width in that - // font, that this width is greater than the width of spaces, and that the - // width of 3 digits is greater than the width of ellipses. - int ToPixels(int width) { - return std::ceil(digit_pixels_ * (width / 100) + - space_pixels_ * ((width % 100) / 10) + - ellipsis_pixels_ * (width % 10)); - } - - // Exercise BounderLabel::GetWrappedText() using the fixture's test label. - base::string16 GetWrappedText(int width) { - return label_->GetWrappedTextForTest(width, lines_); - } - - // Exercise BounderLabel::GetLinesForWidthAndLimit() using the test label. - int GetLinesForWidth(int width) { - label_->SetBounds(0, 0, width, font_list_.GetHeight() * lines_); - return label_->GetLinesForWidthAndLimit(width, lines_); - } - - protected: - // Creates a label to test with. Returns this fixture, which can be used to - // test the newly created label using the exercise methods above. - BoundedLabelTest& Label(base::string16 text, int lines) { - lines_ = lines; - label_.reset(new BoundedLabel(text, font_list_)); - label_->SetLineLimit(lines_); - return *this; - } - - private: - // The default font list, which will be used for tests. - gfx::FontList font_list_; - float digit_pixels_; - float space_pixels_; - float ellipsis_pixels_; - std::unique_ptr<BoundedLabel> label_; - int lines_; -}; - -/* Test macro *****************************************************************/ - -#define TEST_WRAP(expected, text, width, lines) \ - EXPECT_EQ(ToString(expected), \ - Label(ToString(text), lines).GetWrappedText(ToPixels(width))) - -#define TEST_LINES(expected, text, width, lines) \ - EXPECT_EQ(expected, \ - Label(ToString(text), lines).GetLinesForWidth(ToPixels(width))) - -/* Elision tests **************************************************************/ - -TEST_F(BoundedLabelTest, GetWrappedTextTest) { -#if defined(OS_MACOSX) - // Skip this test on macOS 10.10, which has slightly different font metrics - // than the other OSes we support. - if (base::mac::IsOS10_10()) - return; -#endif - - // One word per line: No ellision should be made when not necessary. - TEST_WRAP("123", "123", 301, 1); - TEST_WRAP("123", "123", 301, 2); - TEST_WRAP("123", "123", 301, 3); - TEST_WRAP("123\n456", "123 456", 301, 2); - TEST_WRAP("123\n456", "123 456", 301, 3); - TEST_WRAP("123\n456\n789", "123 456 789", 301, 3); - - // One word per line: Ellisions should be made when necessary. - TEST_WRAP("123...", "123 456", 302, 1); - TEST_WRAP("123...", "123 456 789", 302, 1); - TEST_WRAP("123\n456...", "123 456 789", 302, 2); - - // Two words per line: No ellision should be made when not necessary. - TEST_WRAP("123 456", "123 456", 621, 1); - TEST_WRAP("123 456", "123 456", 621, 2); - TEST_WRAP("123 456", "123 456", 621, 3); - TEST_WRAP("123 456\n789 012", "123 456 789 012", 621, 2); - TEST_WRAP("123 456\n789 012", "123 456 789 012", 621, 3); - TEST_WRAP("123 456\n789 012\n345 678", "123 456 789 012 345 678", 621, 3); - - // Two words per line: Ellisions should be made when necessary. - TEST_WRAP("123 456...", "123 456 789 012", 621, 1); - TEST_WRAP("123 456...", "123 456 789 012 345 678", 621, 1); - TEST_WRAP("123 456\n789 012...", "123 456 789 012 345 678", 621, 2); - - // Single trailing spaces: No ellipses should be added. - TEST_WRAP("123", "123 ", 301, 1); - TEST_WRAP("123\n456", "123 456 ", 301, 2); - TEST_WRAP("123\n456\n789", "123 456 789 ", 301, 3); - TEST_WRAP("123 456", "123 456 ", 611, 1); - TEST_WRAP("123 456\n789 012", "123 456 789 012 ", 611, 2); - TEST_WRAP("123 456\n789 012\n345 678", "123 456 789 012 345 678 ", 611, 3); - - // Multiple trailing spaces: No ellipses should be added. - TEST_WRAP("123", "123 ", 301, 1); - TEST_WRAP("123\n456", "123 456 ", 301, 2); - TEST_WRAP("123\n456\n789", "123 456 789 ", 301, 3); - TEST_WRAP("123 456", "123 456 ", 611, 1); - TEST_WRAP("123 456\n789 012", "123 456 789 012 ", 611, 2); - TEST_WRAP("123 456\n789 012\n345 678", - "123 456 789 012 345 678 ", 611, 3); - - // Multiple spaces between words on the same line: Spaces should be preserved. - // Test cases for single spaces between such words are included in the "Two - // words per line" sections above. - TEST_WRAP("123 456", "123 456", 621, 1); - TEST_WRAP("123 456...", "123 456 789 012", 631, 1); - TEST_WRAP("123 456\n789 012", "123 456 789 012", 631, 2); - TEST_WRAP("123 456...", "123 456 789 012 345 678", 621, 1); - TEST_WRAP("123 456\n789 012...", "123 456 789 012 345 678", 631, 2); - TEST_WRAP("123 456\n789 012\n345 678", - "123 456 789 012 345 678", 641, 3); - - // Multiple spaces between words split across lines: Spaces should be removed - // even if lines are wide enough to include those spaces. Test cases for - // single spaces between such words are included in the "Two words per line" - // sections above. - TEST_WRAP("123\n456", "123 456", 321, 2); - TEST_WRAP("123\n456", "123 456", 391, 2); - TEST_WRAP("123\n456...", "123 456 789", 321, 2); - TEST_WRAP("123\n456...", "123 456 789", 391, 2); - TEST_WRAP("123 456\n789 012", "123 456 789 012", 641, 2); - TEST_WRAP("123 456\n789 012...", "123 456 789 012 345 678", 641, 2); - - // Long words without spaces should be wrapped when necessary. - TEST_WRAP("123\n456", "123456", 300, 9); - - // TODO(dharcourt): Add test cases to verify that: - // - Spaces before elisions are removed - // - Leading spaces are preserved - // - Words are split when they are longer than lines - // - Words are clipped when they are longer than the last line - // - No blank line are created before or after clipped word - // - Spaces at the end of the text are removed - - // TODO(dharcourt): Add test cases for: - // - Empty and very large strings - // - Zero, very large, and negative line limit values - // - Other input boundary conditions - // TODO(dharcourt): Add some randomly generated fuzz test cases. -} - -/* GetLinesTest ***************************************************************/ - -TEST_F(BoundedLabelTest, GetLinesTest) { - // Zero and negative width values should yield zero lines. - TEST_LINES(0, "123 456", 0, 1); - TEST_LINES(0, "123 456", -1, 1); - TEST_LINES(0, "123 456", -2, 1); - TEST_LINES(0, "123 456", std::numeric_limits<int>::min(), 1); - - // Small width values should yield one word per line. - TEST_LINES(1, "123 456", 1, 1); - TEST_LINES(2, "123 456", 1, 2); - TEST_LINES(1, "123 456", 2, 1); - TEST_LINES(2, "123 456", 2, 2); - TEST_LINES(1, "123 456", 3, 1); - TEST_LINES(2, "123 456", 3, 2); - - // Large width values should yield all words on one line. - TEST_LINES(1, "123 456", 610, 1); - TEST_LINES(1, "123 456", std::numeric_limits<int>::max(), 1); -} - -/* Other tests ****************************************************************/ - -// TODO(dharcourt): Add test cases to verify that: -// - SetMaxLines() affects the return values of some methods but not others. -// - Bound changes affects GetPreferredLines(), GetTextSize(), and -// GetWrappedText() return values. -// - GetTextFlags are as expected. - -} // namespace test - -} // namespace message_center diff --git a/chromium/ui/message_center/views/message_popup_collection.cc b/chromium/ui/message_center/views/message_popup_collection.cc index ddc6be93c23..67b55fd8a38 100644 --- a/chromium/ui/message_center/views/message_popup_collection.cc +++ b/chromium/ui/message_center/views/message_popup_collection.cc @@ -197,6 +197,15 @@ void MessagePopupCollection::AnimationCanceled( Update(); } +MessagePopupView* MessagePopupCollection::GetPopupViewForNotificationID( + const std::string& notification_id) { + for (const auto& item : popup_items_) { + if (item.id == notification_id) + return item.popup; + } + return nullptr; +} + MessagePopupView* MessagePopupCollection::CreatePopup( const Notification& notification) { return new MessagePopupView(notification, alignment_delegate_, this); diff --git a/chromium/ui/message_center/views/message_popup_collection.h b/chromium/ui/message_center/views/message_popup_collection.h index 2bab0cbd5c4..44656e96fa2 100644 --- a/chromium/ui/message_center/views/message_popup_collection.h +++ b/chromium/ui/message_center/views/message_popup_collection.h @@ -58,6 +58,11 @@ class MESSAGE_CENTER_EXPORT MessagePopupCollection void AnimationProgressed(const gfx::Animation* animation) override; void AnimationCanceled(const gfx::Animation* animation) override; + // Find the message popup view for the given notification id. Return nullptr + // if it does not exist. + MessagePopupView* GetPopupViewForNotificationID( + const std::string& notification_id); + void set_inverse() { inverse_ = true; } protected: diff --git a/chromium/ui/message_center/views/message_popup_collection_unittest.cc b/chromium/ui/message_center/views/message_popup_collection_unittest.cc index acbae665e36..b412236dd07 100644 --- a/chromium/ui/message_center/views/message_popup_collection_unittest.cc +++ b/chromium/ui/message_center/views/message_popup_collection_unittest.cc @@ -141,11 +141,11 @@ class MockMessagePopupView : public MessagePopupView { void AutoCollapse() override { if (expandable_) - child_at(0)->SetPreferredSize(gfx::Size(kNotificationWidth, 42)); + children().front()->SetPreferredSize(gfx::Size(kNotificationWidth, 42)); } void SetPreferredHeight(int height) { - child_at(0)->SetPreferredSize(gfx::Size(kNotificationWidth, height)); + children().front()->SetPreferredSize(gfx::Size(kNotificationWidth, height)); } void SetHovered(bool is_hovered) { diff --git a/chromium/ui/message_center/views/message_popup_view.cc b/chromium/ui/message_center/views/message_popup_view.cc index a4e333c54c4..33f2ca71bd5 100644 --- a/chromium/ui/message_center/views/message_popup_view.cc +++ b/chromium/ui/message_center/views/message_popup_view.cc @@ -4,7 +4,6 @@ #include "ui/message_center/views/message_popup_view.h" -#include "base/feature_list.h" #include "build/build_config.h" #include "ui/accessibility/ax_enums.mojom.h" #include "ui/accessibility/ax_node_data.h" @@ -12,11 +11,9 @@ #include "ui/aura/window_targeter.h" #include "ui/display/display.h" #include "ui/display/screen.h" -#include "ui/message_center/public/cpp/features.h" #include "ui/message_center/public/cpp/message_center_constants.h" #include "ui/message_center/views/message_popup_collection.h" #include "ui/message_center/views/message_view.h" -#include "ui/message_center/views/message_view_context_menu_controller.h" #include "ui/message_center/views/message_view_factory.h" #include "ui/message_center/views/popup_alignment_delegate.h" #include "ui/views/layout/fill_layout.h" @@ -37,14 +34,6 @@ MessagePopupView::MessagePopupView(const Notification& notification, a11y_feedback_on_init_( notification.rich_notification_data() .should_make_spoken_feedback_for_popup_updates) { -#if !defined(OS_CHROMEOS) - if (!base::FeatureList::IsEnabled(message_center::kNewStyleNotifications)) { - context_menu_controller_ = - std::make_unique<MessageViewContextMenuController>(); - message_view_->set_context_menu_controller(context_menu_controller_.get()); - } -#endif - SetLayoutManager(std::make_unique<views::FillLayout>()); if (!message_view_->IsManuallyExpandedOrCollapsed()) diff --git a/chromium/ui/message_center/views/message_popup_view.h b/chromium/ui/message_center/views/message_popup_view.h index 0be0187b104..629d2da829f 100644 --- a/chromium/ui/message_center/views/message_popup_view.h +++ b/chromium/ui/message_center/views/message_popup_view.h @@ -13,7 +13,6 @@ namespace message_center { class MessagePopupCollection; class MessageView; -class MessageViewContextMenuController; class Notification; class PopupAlignmentDelegate; @@ -81,8 +80,6 @@ class MESSAGE_CENTER_EXPORT MessagePopupView : public views::WidgetDelegateView, PopupAlignmentDelegate* const alignment_delegate_; MessagePopupCollection* const popup_collection_; - std::unique_ptr<MessageViewContextMenuController> context_menu_controller_; - const bool a11y_feedback_on_init_; bool is_hovered_ = false; bool is_active_ = false; diff --git a/chromium/ui/message_center/views/message_view.cc b/chromium/ui/message_center/views/message_view.cc index 4817b5a2056..65bee0e9876 100644 --- a/chromium/ui/message_center/views/message_view.cc +++ b/chromium/ui/message_center/views/message_view.cc @@ -4,13 +4,11 @@ #include "ui/message_center/views/message_view.h" -#include "base/feature_list.h" #include "base/strings/utf_string_conversions.h" #include "build/build_config.h" #include "ui/accessibility/ax_enums.mojom.h" #include "ui/accessibility/ax_node_data.h" #include "ui/base/l10n/l10n_util.h" -#include "ui/base/models/simple_menu_model.h" #include "ui/compositor/paint_recorder.h" #include "ui/compositor/scoped_layer_animation_settings.h" #include "ui/gfx/canvas.h" @@ -18,7 +16,6 @@ #include "ui/gfx/shadow_util.h" #include "ui/gfx/shadow_value.h" #include "ui/message_center/message_center.h" -#include "ui/message_center/public/cpp/features.h" #include "ui/message_center/public/cpp/message_center_constants.h" #include "ui/message_center/views/notification_background_painter.h" #include "ui/message_center/views/notification_control_buttons_view.h" @@ -130,6 +127,10 @@ void MessageView::CloseSwipeControl() { slide_out_controller_.CloseSwipeControl(); } +void MessageView::SlideOutAndClose(int direction) { + slide_out_controller_.SlideOutAndClose(direction); +} + void MessageView::SetExpanded(bool expanded) { // Not implemented by default. } @@ -304,24 +305,31 @@ ui::Layer* MessageView::GetSlideOutLayer() { } void MessageView::OnSlideStarted() { - for (auto* observer : slide_observers_) { - observer->OnSlideStarted(notification_id_); + for (auto& observer : slide_observers_) { + observer.OnSlideStarted(notification_id_); } } void MessageView::OnSlideChanged(bool in_progress) { - for (auto* observer : slide_observers_) { - observer->OnSlideChanged(notification_id_); + for (auto& observer : slide_observers_) { + observer.OnSlideChanged(notification_id_); } } void MessageView::AddSlideObserver(MessageView::SlideObserver* observer) { - slide_observers_.push_back(observer); + slide_observers_.AddObserver(observer); +} + +void MessageView::RemoveSlideObserver(MessageView::SlideObserver* observer) { + slide_observers_.RemoveObserver(observer); } void MessageView::OnSlideOut() { MessageCenter::Get()->RemoveNotification(notification_id_, true /* by_user */); + + for (auto& observer : slide_observers_) + observer.OnSlideOut(notification_id_); } void MessageView::OnWillChangeFocus(views::View* before, views::View* now) {} diff --git a/chromium/ui/message_center/views/message_view.h b/chromium/ui/message_center/views/message_view.h index 8b59c163bab..c9f0809b92a 100644 --- a/chromium/ui/message_center/views/message_view.h +++ b/chromium/ui/message_center/views/message_view.h @@ -8,6 +8,7 @@ #include <memory> #include "base/macros.h" +#include "base/observer_list.h" #include "base/strings/string16.h" #include "third_party/skia/include/core/SkBitmap.h" #include "third_party/skia/include/core/SkColor.h" @@ -54,6 +55,7 @@ class MESSAGE_CENTER_EXPORT MessageView : public views::InkDropHostView, virtual void OnSlideStarted(const std::string& notification_id) {} virtual void OnSlideChanged(const std::string& notification_id) {} + virtual void OnSlideOut(const std::string& notification_id) {} }; enum class Mode { @@ -91,6 +93,7 @@ class MESSAGE_CENTER_EXPORT MessageView : public views::InkDropHostView, virtual bool IsManuallyExpandedOrCollapsed() const; virtual void SetManuallyExpandedOrCollapsed(bool value); virtual void CloseSwipeControl(); + virtual void SlideOutAndClose(int direction); // Update corner radii of the notification. Subclasses will override this to // implement rounded corners if they don't use MessageView's default @@ -135,6 +138,7 @@ class MESSAGE_CENTER_EXPORT MessageView : public views::InkDropHostView, void OnDidChangeFocus(views::View* before, views::View* now) override; void AddSlideObserver(SlideObserver* observer); + void RemoveSlideObserver(SlideObserver* observer); Mode GetMode() const; @@ -189,7 +193,7 @@ class MESSAGE_CENTER_EXPORT MessageView : public views::InkDropHostView, std::unique_ptr<views::Painter> focus_painter_; SlideOutController slide_out_controller_; - std::vector<SlideObserver*> slide_observers_; + base::ObserverList<SlideObserver>::Unchecked slide_observers_; // True if |this| is embedded in another view. Equivalent to |!top_level| in // MessageViewFactory parlance. diff --git a/chromium/ui/message_center/views/message_view_context_menu_controller.cc b/chromium/ui/message_center/views/message_view_context_menu_controller.cc deleted file mode 100644 index 8b043caa3bd..00000000000 --- a/chromium/ui/message_center/views/message_view_context_menu_controller.cc +++ /dev/null @@ -1,57 +0,0 @@ -// Copyright 2013 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 "ui/message_center/views/message_view_context_menu_controller.h" - -#include "base/bind.h" -#include "ui/base/models/menu_model.h" -#include "ui/message_center/message_center.h" -#include "ui/message_center/views/message_view.h" -#include "ui/message_center/views/notification_menu_model.h" -#include "ui/views/controls/menu/menu_model_adapter.h" -#include "ui/views/controls/menu/menu_runner.h" -#include "ui/views/widget/widget.h" - -namespace message_center { - -MessageViewContextMenuController::MessageViewContextMenuController() = default; - -MessageViewContextMenuController::~MessageViewContextMenuController() = default; - -void MessageViewContextMenuController::ShowContextMenuForViewImpl( - views::View* source, - const gfx::Point& point, - ui::MenuSourceType source_type) { - // Assumes that the target view has to be MessageView. - MessageView* message_view = static_cast<MessageView*>(source); - Notification* notification = - MessageCenter::Get()->FindVisibleNotificationById( - message_view->notification_id()); - - // Notification is null if the notification view is being removed or some - // invalid status. In this case, just returns. - if (!notification) - return; - - menu_model_ = std::make_unique<NotificationMenuModel>(*notification); - - if (!menu_model_ || menu_model_->GetItemCount() == 0) - return; - - menu_runner_ = std::make_unique<views::MenuRunner>( - menu_model_.get(), views::MenuRunner::HAS_MNEMONICS, - base::Bind(&MessageViewContextMenuController::OnMenuClosed, - base::Unretained(this))); - - menu_runner_->RunMenuAt(source->GetWidget()->GetTopLevelWidget(), NULL, - gfx::Rect(point, gfx::Size()), - views::MenuAnchorPosition::kTopRight, source_type); -} - -void MessageViewContextMenuController::OnMenuClosed() { - menu_runner_.reset(); - menu_model_.reset(); -} - -} // namespace message_center diff --git a/chromium/ui/message_center/views/message_view_context_menu_controller.h b/chromium/ui/message_center/views/message_view_context_menu_controller.h deleted file mode 100644 index 00bf1727253..00000000000 --- a/chromium/ui/message_center/views/message_view_context_menu_controller.h +++ /dev/null @@ -1,48 +0,0 @@ -// Copyright 2013 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 UI_MESSAGE_CENTER_VIEWS_MESSAGE_VIEW_CONTEXT_MENU_CONTROLLER_H_ -#define UI_MESSAGE_CENTER_VIEWS_MESSAGE_VIEW_CONTEXT_MENU_CONTROLLER_H_ - -#include <memory> - -#include "base/compiler_specific.h" -#include "base/macros.h" -#include "ui/message_center/message_center_export.h" -#include "ui/views/context_menu_controller.h" - -namespace ui { -class MenuModel; -} // namespace ui - -namespace views { -class MenuRunner; -} // namespace views - -namespace message_center { - -class MESSAGE_CENTER_EXPORT MessageViewContextMenuController - : public views::ContextMenuController { - public: - explicit MessageViewContextMenuController(); - ~MessageViewContextMenuController() override; - - private: - // Overridden from views::ContextMenuController: - void ShowContextMenuForViewImpl(views::View* source, - const gfx::Point& point, - ui::MenuSourceType source_type) override; - - // Callback for MenuRunner - void OnMenuClosed(); - - std::unique_ptr<ui::MenuModel> menu_model_; - std::unique_ptr<views::MenuRunner> menu_runner_; - - DISALLOW_COPY_AND_ASSIGN(MessageViewContextMenuController); -}; - -} // namespace message_center - -#endif // UI_MESSAGE_CENTER_VIEWS_MESSAGE_VIEW_CONTEXT_MENU_CONTROLLER_H_ diff --git a/chromium/ui/message_center/views/message_view_factory.cc b/chromium/ui/message_center/views/message_view_factory.cc index 8db23c841cc..e3915498a9f 100644 --- a/chromium/ui/message_center/views/message_view_factory.cc +++ b/chromium/ui/message_center/views/message_view_factory.cc @@ -6,17 +6,10 @@ #include <vector> -#include "base/command_line.h" -#include "base/feature_list.h" #include "base/lazy_instance.h" -#include "ui/message_center/public/cpp/features.h" #include "ui/message_center/public/cpp/notification_types.h" #include "ui/message_center/views/notification_view_md.h" -#if !defined(OS_CHROMEOS) -#include "ui/message_center/views/notification_view.h" -#endif - namespace message_center { namespace { @@ -63,17 +56,8 @@ MessageView* MessageViewFactory::Create(const Notification& notification) { break; } - if (!notification_view) { -#if defined(OS_CHROMEOS) + if (!notification_view) notification_view = new NotificationViewMD(notification); -#else - // All above roads lead to the generic NotificationView. - if (base::FeatureList::IsEnabled(message_center::kNewStyleNotifications)) - notification_view = new NotificationViewMD(notification); - else - notification_view = new NotificationView(notification); -#endif - } return notification_view; } diff --git a/chromium/ui/message_center/views/notification_button.cc b/chromium/ui/message_center/views/notification_button.cc index 6f50e00ff2c..a015eddd53e 100644 --- a/chromium/ui/message_center/views/notification_button.cc +++ b/chromium/ui/message_center/views/notification_button.cc @@ -43,8 +43,8 @@ void NotificationButton::SetIcon(const gfx::ImageSkia& image) { icon_->SetImageSize( gfx::Size(kNotificationButtonIconSize, kNotificationButtonIconSize)); icon_->SetImage(image); - icon_->SetHorizontalAlignment(views::ImageView::LEADING); - icon_->SetVerticalAlignment(views::ImageView::LEADING); + icon_->SetHorizontalAlignment(views::ImageView::Alignment::kLeading); + icon_->SetVerticalAlignment(views::ImageView::Alignment::kLeading); icon_->SetBorder(views::CreateEmptyBorder(kButtonIconTopPadding, 0, 0, 0)); AddChildViewAt(icon_, 0); } diff --git a/chromium/ui/message_center/views/notification_header_view.cc b/chromium/ui/message_center/views/notification_header_view.cc index 58a9a8b8333..998b553052e 100644 --- a/chromium/ui/message_center/views/notification_header_view.cc +++ b/chromium/ui/message_center/views/notification_header_view.cc @@ -67,6 +67,9 @@ constexpr wchar_t kNotificationHeaderDivider[] = L" \u2022 "; // "Roboto-Regular, 12sp" is specified in the mock. constexpr int kHeaderTextFontSize = 12; +// Minimum spacing before the control buttons. +constexpr int kControlButtonSpacing = 16; + // ExpandButtton forwards all mouse and key events to NotificationHeaderView, // but takes tab focus for accessibility purpose. class ExpandButton : public views::ImageView { @@ -156,7 +159,7 @@ NotificationHeaderView::NotificationHeaderView(views::ButtonListener* listener) const views::FlexSpecification kSpacerFlex = views::FlexSpecification::ForSizeRule( - views::MinimumFlexSizeRule::kScaleToZero, + views::MinimumFlexSizeRule::kScaleToMinimum, views::MaximumFlexSizeRule::kUnbounded) .WithOrder(2); @@ -169,8 +172,8 @@ NotificationHeaderView::NotificationHeaderView(views::ButtonListener* listener) app_icon_view_ = new views::ImageView(); app_icon_view_->SetImageSize(gfx::Size(kSmallImageSizeMD, kSmallImageSizeMD)); app_icon_view_->SetBorder(views::CreateEmptyBorder(kAppIconPadding)); - app_icon_view_->SetVerticalAlignment(views::ImageView::LEADING); - app_icon_view_->SetHorizontalAlignment(views::ImageView::LEADING); + app_icon_view_->SetVerticalAlignment(views::ImageView::Alignment::kLeading); + app_icon_view_->SetHorizontalAlignment(views::ImageView::Alignment::kLeading); DCHECK_EQ(kInnerHeaderHeight, app_icon_view_->GetPreferredSize().height()); AddChildView(app_icon_view_); @@ -221,15 +224,16 @@ NotificationHeaderView::NotificationHeaderView(views::ButtonListener* listener) // Expand button view expand_button_ = new ExpandButton(); expand_button_->SetBorder(views::CreateEmptyBorder(kExpandIconViewPadding)); - expand_button_->SetVerticalAlignment(views::ImageView::LEADING); - expand_button_->SetHorizontalAlignment(views::ImageView::LEADING); + expand_button_->SetVerticalAlignment(views::ImageView::Alignment::kLeading); + expand_button_->SetHorizontalAlignment(views::ImageView::Alignment::kLeading); expand_button_->SetImageSize(gfx::Size(kExpandIconSize, kExpandIconSize)); DCHECK_EQ(kInnerHeaderHeight, expand_button_->GetPreferredSize().height()); AddChildView(expand_button_); // Spacer between left-aligned views and right-aligned views views::View* spacer = new views::View; - spacer->SetPreferredSize(gfx::Size(1, kInnerHeaderHeight)); + spacer->SetPreferredSize( + gfx::Size(kControlButtonSpacing, kInnerHeaderHeight)); AddChildView(spacer); layout->SetFlexForView(spacer, kSpacerFlex); @@ -237,6 +241,8 @@ NotificationHeaderView::NotificationHeaderView(views::ButtonListener* listener) SetPreferredSize(gfx::Size(kNotificationWidth, kHeaderHeight)); } +NotificationHeaderView::~NotificationHeaderView() = default; + void NotificationHeaderView::SetAppIcon(const gfx::ImageSkia& img) { app_icon_view_->SetImage(img); using_default_app_icon_ = false; @@ -305,7 +311,7 @@ void NotificationHeaderView::SetTimestamp(base::Time timestamp) { &relative_time, &next_update); timestamp_view_->SetText(relative_time); - has_timestamp_ = true; + timestamp_ = timestamp; UpdateSummaryTextVisibility(); // Unretained is safe as the timer cancels the task on destruction. @@ -315,16 +321,21 @@ void NotificationHeaderView::SetTimestamp(base::Time timestamp) { base::Unretained(this), timestamp)); } -void NotificationHeaderView::ClearTimestamp() { - has_timestamp_ = false; - timestamp_update_timer_.Stop(); +void NotificationHeaderView::SetTimestampVisible(bool visible) { + timestamp_visible_ = visible; + + if (visible && timestamp_) + SetTimestamp(timestamp_.value()); + else + timestamp_update_timer_.Stop(); + UpdateSummaryTextVisibility(); } void NotificationHeaderView::SetExpandButtonEnabled(bool enabled) { // SetInkDropMode iff. the visibility changed. // Otherwise, the ink drop animation cannot finish. - if (expand_button_->visible() != enabled) + if (expand_button_->GetVisible() != enabled) SetInkDropMode(enabled ? InkDropMode::ON : InkDropMode::OFF); expand_button_->SetVisible(enabled); @@ -363,7 +374,7 @@ void NotificationHeaderView::SetBackgroundColor(SkColor color) { } bool NotificationHeaderView::IsExpandButtonEnabled() { - return expand_button_->visible(); + return expand_button_->GetVisible(); } void NotificationHeaderView::SetSubpixelRenderingEnabled(bool enabled) { @@ -391,11 +402,15 @@ const base::string16& NotificationHeaderView::timestamp_for_testing() const { } void NotificationHeaderView::UpdateSummaryTextVisibility() { - const bool visible = !summary_text_view_->text().empty(); - summary_text_divider_->SetVisible(visible); - summary_text_view_->SetVisible(visible); - timestamp_divider_->SetVisible(!has_progress_ && has_timestamp_); - timestamp_view_->SetVisible(!has_progress_ && has_timestamp_); + const bool summary_visible = !summary_text_view_->text().empty(); + summary_text_divider_->SetVisible(summary_visible); + summary_text_view_->SetVisible(summary_visible); + + const bool timestamp_visible = + !has_progress_ && timestamp_visible_ && timestamp_; + timestamp_divider_->SetVisible(timestamp_visible); + timestamp_view_->SetVisible(timestamp_visible); + Layout(); } diff --git a/chromium/ui/message_center/views/notification_header_view.h b/chromium/ui/message_center/views/notification_header_view.h index 8278caaf83c..e67234d3385 100644 --- a/chromium/ui/message_center/views/notification_header_view.h +++ b/chromium/ui/message_center/views/notification_header_view.h @@ -6,6 +6,7 @@ #define UI_MESSAGE_CENTER_VIEWS_NOTIFICATION_HEADER_VIEW_H_ #include "base/macros.h" +#include "base/optional.h" #include "base/timer/timer.h" #include "ui/gfx/text_constants.h" #include "ui/message_center/message_center_export.h" @@ -22,6 +23,7 @@ namespace message_center { class MESSAGE_CENTER_EXPORT NotificationHeaderView : public views::Button { public: explicit NotificationHeaderView(views::ButtonListener* listener); + ~NotificationHeaderView() override; void SetAppIcon(const gfx::ImageSkia& img); void SetAppName(const base::string16& name); void SetAppNameElideBehavior(gfx::ElideBehavior elide_behavior); @@ -33,6 +35,7 @@ class MESSAGE_CENTER_EXPORT NotificationHeaderView : public views::Button { void SetOverflowIndicator(int count); void SetTimestamp(base::Time timestamp); + void SetTimestampVisible(bool visible); void SetExpandButtonEnabled(bool enabled); void SetExpanded(bool expanded); void SetSettingsButtonEnabled(bool enabled); @@ -49,7 +52,6 @@ class MESSAGE_CENTER_EXPORT NotificationHeaderView : public views::Button { void ClearAppIcon(); void ClearProgress(); - void ClearTimestamp(); bool IsExpandButtonEnabled(); void SetSubpixelRenderingEnabled(bool enabled); @@ -81,6 +83,7 @@ class MESSAGE_CENTER_EXPORT NotificationHeaderView : public views::Button { // Timer that updates the timestamp over time. base::OneShotTimer timestamp_update_timer_; + base::Optional<base::Time> timestamp_; views::Label* app_name_view_ = nullptr; views::Label* summary_text_divider_ = nullptr; @@ -92,7 +95,7 @@ class MESSAGE_CENTER_EXPORT NotificationHeaderView : public views::Button { bool settings_button_enabled_ = false; bool has_progress_ = false; - bool has_timestamp_ = false; + bool timestamp_visible_ = true; bool is_expanded_ = false; bool using_default_app_icon_ = false; diff --git a/chromium/ui/message_center/views/notification_menu_model.cc b/chromium/ui/message_center/views/notification_menu_model.cc deleted file mode 100644 index 0f88fa83e2b..00000000000 --- a/chromium/ui/message_center/views/notification_menu_model.cc +++ /dev/null @@ -1,51 +0,0 @@ -// Copyright 2017 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 "ui/message_center/views/notification_menu_model.h" - -#include <memory> - -#include "base/macros.h" -#include "base/strings/utf_string_conversions.h" -#include "ui/base/l10n/l10n_util.h" -#include "ui/base/models/simple_menu_model.h" -#include "ui/message_center/message_center.h" -#include "ui/strings/grit/ui_strings.h" - -namespace message_center { - -namespace { - -// Menu constants -const int kTogglePermissionCommand = 0; - -} // namespace - -NotificationMenuModel::NotificationMenuModel(const Notification& notification) - : ui::SimpleMenuModel(this), notification_id_(notification.id()) { - DCHECK(!notification.display_source().empty()); - AddItem(kTogglePermissionCommand, - l10n_util::GetStringFUTF16(IDS_MESSAGE_CENTER_NOTIFIER_DISABLE, - notification.display_source())); -} - -NotificationMenuModel::~NotificationMenuModel() {} - -bool NotificationMenuModel::IsCommandIdChecked(int command_id) const { - return false; -} - -bool NotificationMenuModel::IsCommandIdEnabled(int command_id) const { - // TODO(estade): commands shouldn't always be enabled. For example, a - // notification's enabled state might be controlled by policy. See - // http://crbug.com/771269 - return true; -} - -void NotificationMenuModel::ExecuteCommand(int command_id, int event_flags) { - DCHECK_EQ(command_id, kTogglePermissionCommand); - MessageCenter::Get()->DisableNotification(notification_id_); -} - -} // namespace message_center diff --git a/chromium/ui/message_center/views/notification_menu_model.h b/chromium/ui/message_center/views/notification_menu_model.h deleted file mode 100644 index 22658b74b00..00000000000 --- a/chromium/ui/message_center/views/notification_menu_model.h +++ /dev/null @@ -1,35 +0,0 @@ -// Copyright 2017 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 UI_MESSAGE_CENTER_NOTIFICATION_MENU_MODEL_H_ -#define UI_MESSAGE_CENTER_NOTIFICATION_MENU_MODEL_H_ - -#include "base/macros.h" -#include "ui/base/models/simple_menu_model.h" -#include "ui/message_center/message_center_export.h" -#include "ui/message_center/public/cpp/notification.h" - -namespace message_center { - -// The model of the context menu for a notification card. -class MESSAGE_CENTER_EXPORT NotificationMenuModel - : public ui::SimpleMenuModel, - public ui::SimpleMenuModel::Delegate { - public: - NotificationMenuModel(const Notification& notification); - ~NotificationMenuModel() override; - - // Overridden from ui::SimpleMenuModel::Delegate: - bool IsCommandIdChecked(int command_id) const override; - bool IsCommandIdEnabled(int command_id) const override; - void ExecuteCommand(int command_id, int event_flags) override; - - private: - const std::string notification_id_; - DISALLOW_COPY_AND_ASSIGN(NotificationMenuModel); -}; - -} // namespace message_center - -#endif // UI_MESSAGE_CENTER_UI_CONTROLLER_H_ diff --git a/chromium/ui/message_center/views/notification_menu_model_unittest.cc b/chromium/ui/message_center/views/notification_menu_model_unittest.cc deleted file mode 100644 index 937ed1c187a..00000000000 --- a/chromium/ui/message_center/views/notification_menu_model_unittest.cc +++ /dev/null @@ -1,102 +0,0 @@ -// Copyright 2017 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 "ui/message_center/views/notification_menu_model.h" - -#include <utility> - -#include "base/macros.h" -#include "base/strings/utf_string_conversions.h" -#include "testing/gtest/include/gtest/gtest.h" -#include "ui/base/models/menu_model.h" -#include "ui/message_center/message_center.h" -#include "ui/message_center/public/cpp/notification.h" -#include "ui/message_center/public/cpp/notification_types.h" - -namespace message_center { -namespace { - -class TestNotificationDelegate : public NotificationDelegate { - public: - TestNotificationDelegate() = default; - - private: - ~TestNotificationDelegate() override = default; - - DISALLOW_COPY_AND_ASSIGN(TestNotificationDelegate); -}; - -} // namespace - -class NotificationMenuModelTest : public testing::Test { - public: - NotificationMenuModelTest() = default; - ~NotificationMenuModelTest() override = default; - - void SetUp() override { - MessageCenter::Initialize(); - message_center_ = MessageCenter::Get(); - } - - void TearDown() override { - message_center_ = NULL; - MessageCenter::Shutdown(); - } - - protected: - NotifierId DummyNotifierId() { return NotifierId(); } - - Notification* AddNotification(const std::string& id) { - return AddNotification(id, DummyNotifierId()); - } - - Notification* AddNotification(const std::string& id, NotifierId notifier_id) { - std::unique_ptr<Notification> notification(new Notification( - NOTIFICATION_TYPE_SIMPLE, id, - base::ASCIIToUTF16("Test Web Notification"), - base::ASCIIToUTF16("Notification message body."), gfx::Image(), - base::ASCIIToUTF16("www.test.org"), GURL(), notifier_id, - RichNotificationData(), new TestNotificationDelegate())); - Notification* notification_ptr = notification.get(); - message_center_->AddNotification(std::move(notification)); - return notification_ptr; - } - MessageCenter* message_center_; - - private: - DISALLOW_COPY_AND_ASSIGN(NotificationMenuModelTest); -}; - -TEST_F(NotificationMenuModelTest, ContextMenuTestWithMessageCenter) { - const std::string id1 = "id1"; - const std::string id2 = "id2"; - const std::string id3 = "id3"; - AddNotification(id1); - - base::string16 display_source = base::ASCIIToUTF16("www.test.org"); - NotifierId notifier_id = DummyNotifierId(); - - NotifierId notifier_id2(NotifierType::APPLICATION, "sample-app"); - std::unique_ptr<Notification> notification = std::make_unique<Notification>( - NOTIFICATION_TYPE_SIMPLE, id2, - base::ASCIIToUTF16("Test Web Notification"), - base::ASCIIToUTF16("Notification message body."), gfx::Image(), - display_source, GURL(), notifier_id2, RichNotificationData(), - new TestNotificationDelegate()); - - std::unique_ptr<ui::MenuModel> model( - std::make_unique<NotificationMenuModel>(*notification)); - message_center_->AddNotification(std::move(notification)); - - AddNotification(id3); - EXPECT_EQ(1, model->GetItemCount()); - - // The first item is to disable notifications from the notifier id. It also - // removes the notification. - EXPECT_EQ(3u, message_center_->GetVisibleNotifications().size()); - model->ActivatedAt(0); - EXPECT_EQ(2u, message_center_->GetVisibleNotifications().size()); -} - -} // namespace message_center diff --git a/chromium/ui/message_center/views/notification_view.cc b/chromium/ui/message_center/views/notification_view.cc deleted file mode 100644 index dd8798be5d0..00000000000 --- a/chromium/ui/message_center/views/notification_view.cc +++ /dev/null @@ -1,657 +0,0 @@ -// Copyright (c) 2012 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 "ui/message_center/views/notification_view.h" - -#include <stddef.h> - -#include "base/command_line.h" -#include "base/macros.h" -#include "base/strings/string_util.h" -#include "build/build_config.h" -#include "components/url_formatter/elide_url.h" -#include "third_party/skia/include/core/SkPaint.h" -#include "third_party/skia/include/core/SkPath.h" -#include "ui/base/cursor/cursor.h" -#include "ui/base/l10n/l10n_util.h" -#include "ui/base/layout.h" -#include "ui/gfx/canvas.h" -#include "ui/gfx/geometry/insets.h" -#include "ui/gfx/geometry/size.h" -#include "ui/gfx/skia_util.h" -#include "ui/gfx/text_elider.h" -#include "ui/message_center/message_center.h" -#include "ui/message_center/message_center_style.h" -#include "ui/message_center/public/cpp/message_center_constants.h" -#include "ui/message_center/public/cpp/notification.h" -#include "ui/message_center/public/cpp/notification_types.h" -#include "ui/message_center/views/bounded_label.h" -#include "ui/message_center/views/notification_button.h" -#include "ui/message_center/views/notification_control_buttons_view.h" -#include "ui/message_center/views/padded_button.h" -#include "ui/message_center/views/proportional_image_view.h" -#include "ui/native_theme/native_theme.h" -#include "ui/strings/grit/ui_strings.h" -#include "ui/views/background.h" -#include "ui/views/border.h" -#include "ui/views/controls/button/image_button.h" -#include "ui/views/controls/image_view.h" -#include "ui/views/controls/label.h" -#include "ui/views/controls/progress_bar.h" -#include "ui/views/layout/box_layout.h" -#include "ui/views/layout/fill_layout.h" -#include "ui/views/native_cursor.h" -#include "ui/views/painter.h" -#include "ui/views/widget/widget.h" -#include "url/gurl.h" - -namespace message_center { - -namespace { - -const int kTextBottomPadding = 12; -const int kItemTitleToMessagePadding = 3; - -// Character limit = pixels per line * line limit / min. pixels per character. -const int kMinPixelsPerTitleCharacter = 4; - -constexpr size_t kMessageCharacterLimit = - kNotificationWidth * kMessageExpandedLineLimit / 3; - -constexpr size_t kContextMessageCharacterLimit = - kNotificationWidth * kContextMessageLineLimit / 3; - -// Dimensions. -const int kProgressBarBottomPadding = 0; - -// static -std::unique_ptr<views::Border> MakeEmptyBorder(int top, - int left, - int bottom, - int right) { - return views::CreateEmptyBorder(top, left, bottom, right); -} - -// static -std::unique_ptr<views::Border> MakeTextBorder(int padding, - int top, - int bottom) { - // Split the padding between the top and the bottom, then add the extra space. - return MakeEmptyBorder(padding / 2 + top, kTextLeftPadding, - (padding + 1) / 2 + bottom, kTextRightPadding); -} - -// static -std::unique_ptr<views::Border> MakeProgressBarBorder(int top, int bottom) { - return MakeEmptyBorder(top, kTextLeftPadding, bottom, kTextRightPadding); -} - -// static -std::unique_ptr<views::Border> MakeSeparatorBorder(int top, - int left, - SkColor color) { - return views::CreateSolidSidedBorder(top, left, 0, 0, color); -} - -#if !defined(OS_CHROMEOS) -// static -void SetBorderRight(views::View* view, int right) { - const gfx::Insets& insets = view->GetInsets(); - if (insets.right() != right) { - view->SetBorder( - MakeEmptyBorder(insets.top(), insets.left(), insets.bottom(), right)); - } -} -#endif - -// NotificationItemView //////////////////////////////////////////////////////// - -// NotificationItemViews are responsible for drawing each list notification -// item's title and message next to each other within a single column. -class NotificationItemView : public views::View { - public: - explicit NotificationItemView(const NotificationItem& item); - private: - DISALLOW_COPY_AND_ASSIGN(NotificationItemView); -}; - -NotificationItemView::NotificationItemView(const NotificationItem& item) { - SetLayoutManager(std::make_unique<views::BoxLayout>( - views::BoxLayout::kHorizontal, gfx::Insets(), - kItemTitleToMessagePadding)); - - views::Label* title = new views::Label(item.title); - title->set_collapse_when_hidden(true); - title->SetHorizontalAlignment(gfx::ALIGN_LEFT); - title->SetEnabledColor(kRegularTextColor); - title->SetAutoColorReadabilityEnabled(false); - AddChildView(title); - - views::Label* message = new views::Label(item.message); - message->set_collapse_when_hidden(true); - message->SetHorizontalAlignment(gfx::ALIGN_LEFT); - message->SetEnabledColor(kDimTextColor); - message->SetAutoColorReadabilityEnabled(false); - AddChildView(message); - - PreferredSizeChanged(); - SchedulePaint(); -} - -} // namespace - -// NotificationView //////////////////////////////////////////////////////////// - -void NotificationView::CreateOrUpdateViews(const Notification& notification) { - top_view_count_ = 0; - - CreateOrUpdateTitleView(notification); - CreateOrUpdateMessageView(notification); - CreateOrUpdateProgressBarView(notification); - CreateOrUpdateListItemViews(notification); - CreateOrUpdateIconView(notification); - CreateOrUpdateSmallIconView(notification); - CreateOrUpdateImageView(notification); - CreateOrUpdateContextMessageView(notification); - CreateOrUpdateActionButtonViews(notification); -} - -NotificationView::NotificationView(const Notification& notification) - : MessageView(notification) { - // Create the top_view_, which collects into a vertical box all content - // at the top of the notification (to the right of the icon) except for the - // close button. - top_view_ = new views::View(); - top_view_->SetLayoutManager( - std::make_unique<views::BoxLayout>(views::BoxLayout::kVertical)); - top_view_->SetBorder( - MakeEmptyBorder(kTextTopPadding - 8, 0, kTextBottomPadding - 5, 0)); - AddChildView(top_view_); - // Create the bottom_view_, which collects into a vertical box all content - // below the notification icon. - bottom_view_ = new views::View(); - bottom_view_->SetLayoutManager( - std::make_unique<views::BoxLayout>(views::BoxLayout::kVertical)); - AddChildView(bottom_view_); - - control_buttons_view_ = new NotificationControlButtonsView(this); - AddChildView(control_buttons_view_); - - views::ImageView* small_image_view = new views::ImageView(); - small_image_view->SetImageSize(gfx::Size(kSmallImageSize, kSmallImageSize)); - small_image_view->set_owned_by_client(); - small_image_view_.reset(small_image_view); - - CreateOrUpdateViews(notification); - - // Put together the different content and control views. Layering those allows - // for proper layout logic and it also allows the control buttons and small - // image to overlap the content as needed to provide large enough click and - // touch areas (<http://crbug.com/168822> and <http://crbug.com/168856>). - AddChildView(small_image_view_.get()); - UpdateControlButtonsVisibilityWithNotification(notification); - - set_notify_enter_exit_on_child(true); -} - -NotificationView::~NotificationView() { -} - -gfx::Size NotificationView::CalculatePreferredSize() const { - int top_width = top_view_->GetPreferredSize().width() + - icon_view_->GetPreferredSize().width(); - int bottom_width = bottom_view_->GetPreferredSize().width(); - int preferred_width = std::max(top_width, bottom_width) + GetInsets().width(); - return gfx::Size(preferred_width, GetHeightForWidth(preferred_width)); -} - -int NotificationView::GetHeightForWidth(int width) const { - // Get the height assuming no line limit changes. - int content_width = width - GetInsets().width(); - int top_height = top_view_->GetHeightForWidth(content_width); - int bottom_height = bottom_view_->GetHeightForWidth(content_width); - - // <http://crbug.com/230448> Fix: Adjust the height when the message_view's - // line limit would be different for the specified width than it currently is. - // TODO(dharcourt): Avoid BoxLayout and directly compute the correct height. - if (message_view_) { - int title_lines = 0; - if (title_view_) { - title_lines = title_view_->GetLinesForWidthAndLimit(width, - kMaxTitleLines); - } - int used_limit = message_view_->GetLineLimit(); - int correct_limit = GetMessageLineLimit(title_lines, width); - if (used_limit != correct_limit) { - top_height -= GetMessageHeight(content_width, used_limit); - top_height += GetMessageHeight(content_width, correct_limit); - } - } - - int content_height = - std::max(top_height, kNotificationIconSize) + bottom_height; - - // Adjust the height to make sure there is at least 16px of space below the - // icon if there is any space there (<http://crbug.com/232966>). - if (content_height > kNotificationIconSize) { - content_height = - std::max(content_height, kNotificationIconSize + kIconBottomPadding); - } - - return content_height + GetInsets().height(); -} - -void NotificationView::Layout() { - // |ShrinkTopmostLabel| updates the borders of views to make space for the - // control buttons. We have to update the borders before calling - // |MessageView::Layout| so that the latest values get taken into account - // while layouting. As |ShrinkTopmostLabel| only depends on the PreferredSize, - // this is valid to do before calling |MessageView::Layout|. - ShrinkTopmostLabel(); - MessageView::Layout(); - - gfx::Insets insets = GetInsets(); - int content_width = width() - insets.width(); - gfx::Rect content_bounds = GetContentsBounds(); - - // Before any resizing, set or adjust the number of message lines. - int title_lines = 0; - if (title_view_) { - title_lines = - title_view_->GetLinesForWidthAndLimit(width(), kMaxTitleLines); - } - if (message_view_) - message_view_->SetLineLimit(GetMessageLineLimit(title_lines, width())); - - // Top views. - int top_height = top_view_->GetHeightForWidth(content_width); - top_view_->SetBounds(insets.left(), insets.top(), content_width, top_height); - - // Icon. - icon_view_->SetBounds(insets.left(), insets.top(), kNotificationIconSize, - kNotificationIconSize); - - // Control buttons (close and settings buttons). - gfx::Rect control_buttons_bounds(content_bounds); - int buttons_width = control_buttons_view_->GetPreferredSize().width(); - int buttons_height = control_buttons_view_->GetPreferredSize().height(); - control_buttons_bounds.set_x(control_buttons_bounds.right() - buttons_width - - kControlButtonPadding); - control_buttons_bounds.set_y(control_buttons_bounds.y() + - kControlButtonPadding); - control_buttons_bounds.set_width(buttons_width); - control_buttons_bounds.set_height(buttons_height); - control_buttons_view_->SetBoundsRect(control_buttons_bounds); - - // Small icon. - gfx::Size small_image_size(small_image_view_->GetPreferredSize()); - gfx::Rect small_image_rect(small_image_size); - small_image_rect.set_origin(gfx::Point( - content_bounds.right() - small_image_size.width() - kSmallImagePadding, - content_bounds.bottom() - small_image_size.height() - - kSmallImagePadding)); - small_image_view_->SetBoundsRect(small_image_rect); - - // Bottom views. - int bottom_y = insets.top() + std::max(top_height, kNotificationIconSize); - int bottom_height = bottom_view_->GetHeightForWidth(content_width); - bottom_view_->SetBounds(insets.left(), bottom_y, - content_width, bottom_height); -} - -void NotificationView::OnFocus() { - MessageView::OnFocus(); - ScrollRectToVisible(GetLocalBounds()); -} - -void NotificationView::ScrollRectToVisible(const gfx::Rect& rect) { - // Notification want to show the whole notification when a part of it (like - // a button) gets focused. - views::View::ScrollRectToVisible(GetLocalBounds()); -} - -void NotificationView::OnMouseEntered(const ui::MouseEvent& event) { - MessageView::OnMouseEntered(event); - UpdateControlButtonsVisibility(); -} - -void NotificationView::OnMouseExited(const ui::MouseEvent& event) { - MessageView::OnMouseExited(event); - UpdateControlButtonsVisibility(); -} - -void NotificationView::UpdateWithNotification( - const Notification& notification) { - MessageView::UpdateWithNotification(notification); - - CreateOrUpdateViews(notification); - UpdateControlButtonsVisibilityWithNotification(notification); - Layout(); - SchedulePaint(); -} - -void NotificationView::ButtonPressed(views::Button* sender, - const ui::Event& event) { - // Certain operations can cause |this| to be destructed, so copy the members - // we send to other parts of the code. - // TODO(dewittj): Remove this hack. - std::string id(notification_id()); - - // See if the button pressed was an action button. - for (size_t i = 0; i < action_buttons_.size(); ++i) { - if (sender == action_buttons_[i]) { - MessageCenter::Get()->ClickOnNotificationButton(id, i); - return; - } - } - - NOTREACHED(); -} - -void NotificationView::CreateOrUpdateTitleView( - const Notification& notification) { - if (notification.title().empty()) { - // Deletion will also remove |title_view_| from its parent. - delete title_view_; - title_view_ = nullptr; - return; - } - - DCHECK(top_view_); - - const gfx::FontList& font_list = - views::Label().font_list().DeriveWithSizeDelta(2); - - constexpr int kTitleCharacterLimit = - kNotificationWidth * kMaxTitleLines / kMinPixelsPerTitleCharacter; - - base::string16 title = gfx::TruncateString( - notification.title(), kTitleCharacterLimit, gfx::WORD_BREAK); - if (!title_view_) { - int padding = kTitleLineHeight - font_list.GetHeight(); - - title_view_ = new BoundedLabel(title, font_list); - title_view_->SetLineHeight(kTitleLineHeight); - title_view_->SetLineLimit(kMaxTitleLines); - title_view_->SetColor(kRegularTextColor); - title_view_->SetBorder(MakeTextBorder(padding, 3, 0)); - top_view_->AddChildViewAt(title_view_, top_view_count_); - } else { - title_view_->SetText(title); - } - - top_view_count_++; -} - -void NotificationView::CreateOrUpdateMessageView( - const Notification& notification) { - if (notification.message().empty()) { - // Deletion will also remove |message_view_| from its parent. - delete message_view_; - message_view_ = nullptr; - return; - } - - DCHECK(top_view_ != NULL); - - base::string16 text = gfx::TruncateString(notification.message(), - kMessageCharacterLimit, - gfx::WORD_BREAK); - if (!message_view_) { - int padding = kMessageLineHeight - views::Label().font_list().GetHeight(); - message_view_ = new BoundedLabel(text); - message_view_->SetLineHeight(kMessageLineHeight); - message_view_->SetColor(kRegularTextColor); - message_view_->SetBorder(MakeTextBorder(padding, 4, 0)); - top_view_->AddChildViewAt(message_view_, top_view_count_); - } else { - message_view_->SetText(text); - } - - message_view_->SetVisible(notification.items().empty()); - top_view_count_++; -} - -base::string16 NotificationView::FormatContextMessage( - const Notification& notification) const { - if (notification.UseOriginAsContextMessage()) { - const GURL url = notification.origin_url(); - DCHECK(url.is_valid()); - return gfx::ElideText( - url_formatter::FormatUrlForSecurityDisplay( - url, url_formatter::SchemeDisplay::OMIT_HTTP_AND_HTTPS), - views::Label().font_list(), kContextMessageViewWidth, gfx::ELIDE_HEAD); - } - - return gfx::TruncateString(notification.context_message(), - kContextMessageCharacterLimit, gfx::WORD_BREAK); -} - -void NotificationView::CreateOrUpdateContextMessageView( - const Notification& notification) { - if (notification.context_message().empty() && - !notification.UseOriginAsContextMessage()) { - // Deletion will also remove |context_message_view_| from its parent. - delete context_message_view_; - context_message_view_ = nullptr; - return; - } - - DCHECK(top_view_ != NULL); - - base::string16 message = FormatContextMessage(notification); - - if (!context_message_view_) { - int padding = kMessageLineHeight - views::Label().font_list().GetHeight(); - context_message_view_ = new BoundedLabel(message); - context_message_view_->SetLineLimit(kContextMessageLineLimit); - context_message_view_->SetLineHeight(kMessageLineHeight); - context_message_view_->SetColor(kDimTextColor); - context_message_view_->SetBorder(MakeTextBorder(padding, 4, 0)); - top_view_->AddChildViewAt(context_message_view_, top_view_count_); - } else { - context_message_view_->SetText(message); - } - - top_view_count_++; -} - -void NotificationView::CreateOrUpdateProgressBarView( - const Notification& notification) { - if (notification.type() != NOTIFICATION_TYPE_PROGRESS) { - // Deletion will also remove |progress_bar_view_| from its parent. - delete progress_bar_view_; - progress_bar_view_ = nullptr; - return; - } - - DCHECK(top_view_); - - if (!progress_bar_view_) { - progress_bar_view_ = new views::ProgressBar(); - progress_bar_view_->SetBorder(MakeProgressBarBorder( - kProgressBarTopPadding, kProgressBarBottomPadding)); - top_view_->AddChildViewAt(progress_bar_view_, top_view_count_); - } - - progress_bar_view_->SetValue(notification.progress() / 100.0); - progress_bar_view_->SetVisible(notification.items().empty()); - top_view_count_++; -} - -void NotificationView::CreateOrUpdateListItemViews( - const Notification& notification) { - for (auto* item_view : item_views_) - delete item_view; - item_views_.clear(); - - int padding = kMessageLineHeight - views::Label().font_list().GetHeight(); - std::vector<NotificationItem> items = notification.items(); - - if (items.size() == 0) - return; - - DCHECK(top_view_); - for (size_t i = 0; i < items.size() && i < kNotificationMaximumItems; ++i) { - NotificationItemView* item_view = new NotificationItemView(items[i]); - item_view->SetBorder(MakeTextBorder(padding, i ? 0 : 4, 0)); - item_views_.push_back(item_view); - top_view_->AddChildViewAt(item_view, top_view_count_++); - } -} - -void NotificationView::CreateOrUpdateIconView( - const Notification& notification) { - gfx::Size image_view_size(kNotificationIconSize, kNotificationIconSize); - - if (!icon_view_) { - icon_view_ = new ProportionalImageView(image_view_size); - AddChildView(icon_view_); - } - - gfx::ImageSkia icon = notification.icon().AsImageSkia(); - icon_view_->SetImage(icon, icon.size()); -} - -void NotificationView::CreateOrUpdateSmallIconView( - const Notification& notification) { - small_image_view_->SetImage(notification.small_image().AsImageSkia()); -} - -void NotificationView::CreateOrUpdateImageView( - const Notification& notification) { - // |image_view_| is the view representing the area covered by the - // notification's image, including background and border. Its size can be - // specified in advance and images will be scaled to fit including a border if - // necessary. - if (notification.image().IsEmpty()) { - delete image_container_; - image_container_ = NULL; - image_view_ = NULL; - return; - } - - gfx::Size ideal_size(kNotificationPreferredImageWidth, - kNotificationPreferredImageHeight); - - if (!image_container_) { - DCHECK(!image_view_); - DCHECK(bottom_view_); - DCHECK_EQ(this, bottom_view_->parent()); - - image_container_ = new views::View(); - image_container_->SetLayoutManager(std::make_unique<views::FillLayout>()); - image_container_->SetBackground( - views::CreateSolidBackground(kImageBackgroundColor)); - - image_view_ = new ProportionalImageView(ideal_size); - image_container_->AddChildView(image_view_); - bottom_view_->AddChildViewAt(image_container_, 0); - } - - DCHECK(image_view_); - image_view_->SetImage(notification.image().AsImageSkia(), ideal_size); - - gfx::Size scaled_size = - GetImageSizeForContainerSize(ideal_size, notification.image().Size()); - image_view_->SetBorder( - ideal_size != scaled_size - ? views::CreateSolidBorder(kNotificationImageBorderSize, - SK_ColorTRANSPARENT) - : NULL); -} - -void NotificationView::CreateOrUpdateActionButtonViews( - const Notification& notification) { - std::vector<ButtonInfo> buttons = notification.buttons(); - bool new_buttons = action_buttons_.size() != buttons.size(); - - if (new_buttons || buttons.size() == 0) { - for (auto* item : separators_) - delete item; - separators_.clear(); - for (auto* item : action_buttons_) - delete item; - action_buttons_.clear(); - } - - DCHECK(bottom_view_); - DCHECK_EQ(this, bottom_view_->parent()); - - for (size_t i = 0; i < buttons.size(); ++i) { - ButtonInfo button_info = buttons[i]; - if (new_buttons) { - views::View* separator = new views::ImageView(); - separator->SetBorder(MakeSeparatorBorder(1, 0, kButtonSeparatorColor)); - separators_.push_back(separator); - bottom_view_->AddChildView(separator); - NotificationButton* button = new NotificationButton(this); - button->SetTitle(button_info.title); - button->SetIcon(button_info.icon.AsImageSkia()); - action_buttons_.push_back(button); - bottom_view_->AddChildView(button); - } else { - action_buttons_[i]->SetTitle(button_info.title); - action_buttons_[i]->SetIcon(button_info.icon.AsImageSkia()); - action_buttons_[i]->SchedulePaint(); - action_buttons_[i]->Layout(); - } - } - - if (new_buttons) { - Layout(); - views::Widget* widget = GetWidget(); - if (widget != NULL) { - widget->SetSize(widget->GetContentsView()->GetPreferredSize()); - GetWidget()->SynthesizeMouseMoveEvent(); - } - } -} - -void NotificationView::UpdateControlButtonsVisibilityWithNotification( - const Notification& notification) { - control_buttons_view_->ShowSettingsButton( - notification.should_show_settings_button()); - control_buttons_view_->ShowCloseButton(GetMode() == - MessageView::Mode::NORMAL); - UpdateControlButtonsVisibility(); -} - -NotificationControlButtonsView* NotificationView::GetControlButtonsView() - const { - return control_buttons_view_; -} - -int NotificationView::GetMessageLineLimit(int title_lines, int width) const { - int effective_title_lines = std::max(0, title_lines - 1); - int line_reduction_from_title = 2 * effective_title_lines; - // Title lines are counted as twice as big as message lines for the purpose - // of this calculation. - // The effect from the title reduction here should be: - // * 0 title lines: 5 max lines message. - // * 1 title line: 5 max lines message. - // * 2 title lines: 3 max lines message. - return std::max(0, kMessageExpandedLineLimit - line_reduction_from_title); -} - -int NotificationView::GetMessageHeight(int width, int limit) const { - return message_view_ ? - message_view_->GetSizeForWidthAndLines(width, limit).height() : 0; -} - -void NotificationView::ShrinkTopmostLabel() { -// Reduce width of the topmost label not to be covered by the control buttons -// only on non Chrome OS platform. -#if !defined(OS_CHROMEOS) - const auto& children = top_view_->children(); - int right = - kTextRightPadding + control_buttons_view_->GetPreferredSize().width(); - for (auto* child : children) { - SetBorderRight(child, right); - right = kTextRightPadding; - } -#endif -} - -} // namespace message_center diff --git a/chromium/ui/message_center/views/notification_view.h b/chromium/ui/message_center/views/notification_view.h deleted file mode 100644 index e2e5507aea1..00000000000 --- a/chromium/ui/message_center/views/notification_view.h +++ /dev/null @@ -1,121 +0,0 @@ -// Copyright (c) 2012 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 UI_MESSAGE_CENTER_VIEWS_NOTIFICATION_VIEW_H_ -#define UI_MESSAGE_CENTER_VIEWS_NOTIFICATION_VIEW_H_ - -#include <vector> - -#include "base/gtest_prod_util.h" -#include "base/macros.h" -#include "ui/message_center/message_center_export.h" -#include "ui/message_center/views/message_view.h" -#include "ui/views/controls/button/button.h" -#include "ui/views/controls/button/image_button.h" - -namespace views { -class ImageView; -class ProgressBar; -} - -namespace message_center { - -class BoundedLabel; -class NotificationButton; -class NotificationControlButtonsView; -class ProportionalImageView; - -// View that displays all current types of notification (web, basic, image, and -// list) except the custom notification. Future notification types may be -// handled by other classes, in which case instances of those classes would be -// returned by the Create() factory method below. -class MESSAGE_CENTER_EXPORT NotificationView : public MessageView, - public views::ButtonListener { - public: - explicit NotificationView(const Notification& notification); - ~NotificationView() override; - - // Overridden from views::View: - gfx::Size CalculatePreferredSize() const override; - int GetHeightForWidth(int width) const override; - void Layout() override; - void OnFocus() override; - void ScrollRectToVisible(const gfx::Rect& rect) override; - void OnMouseEntered(const ui::MouseEvent& event) override; - void OnMouseExited(const ui::MouseEvent& event) override; - - // Overridden from MessageView: - void UpdateWithNotification(const Notification& notification) override; - void ButtonPressed(views::Button* sender, const ui::Event& event) override; - NotificationControlButtonsView* GetControlButtonsView() const override; - - private: - FRIEND_TEST_ALL_PREFIXES(NotificationViewTest, CreateOrUpdateTest); - FRIEND_TEST_ALL_PREFIXES(NotificationViewTest, - CreateOrUpdateTestSettingsButton); - FRIEND_TEST_ALL_PREFIXES(NotificationViewTest, FormatContextMessageTest); - FRIEND_TEST_ALL_PREFIXES(NotificationViewTest, SettingsButtonTest); - FRIEND_TEST_ALL_PREFIXES(NotificationViewTest, TestLineLimits); - FRIEND_TEST_ALL_PREFIXES(NotificationViewTest, TestIconSizing); - FRIEND_TEST_ALL_PREFIXES(NotificationViewTest, TestImageSizing); - FRIEND_TEST_ALL_PREFIXES(NotificationViewTest, TitleWrappingTest); - FRIEND_TEST_ALL_PREFIXES(NotificationViewTest, UpdateButtonsStateTest); - FRIEND_TEST_ALL_PREFIXES(NotificationViewTest, UpdateButtonCountTest); - FRIEND_TEST_ALL_PREFIXES(NotificationViewTest, UpdateViewsOrderingTest); - - friend class NotificationViewTest; - - void CreateOrUpdateViews(const Notification& notification); - - void CreateOrUpdateTitleView(const Notification& notification); - void CreateOrUpdateMessageView(const Notification& notification); - void CreateOrUpdateContextMessageView(const Notification& notification); - void CreateOrUpdateProgressBarView(const Notification& notification); - void CreateOrUpdateListItemViews(const Notification& notification); - void CreateOrUpdateIconView(const Notification& notification); - void CreateOrUpdateSmallIconView(const Notification& notification); - void CreateOrUpdateImageView(const Notification& notification); - void CreateOrUpdateActionButtonViews(const Notification& notification); - // TODO(yoshiki): Move this to MessageView - void UpdateControlButtonsVisibilityWithNotification( - const Notification& notification); - - int GetMessageLineLimit(int title_lines, int width) const; - int GetMessageHeight(int width, int limit) const; - - // Formats the context message to be displayed based on |context| - // so it shows as much information as possible - // given the space available in the ContextMessage section of the - // notification. - base::string16 FormatContextMessage(const Notification& notification) const; - - // Shrink the topmost label not to be covered by the control button. - void ShrinkTopmostLabel(); - - // Weak references to NotificationView descendants owned by their parents. - views::View* top_view_ = nullptr; - BoundedLabel* title_view_ = nullptr; - BoundedLabel* message_view_ = nullptr; - BoundedLabel* context_message_view_ = nullptr; - std::vector<views::View*> item_views_; - ProportionalImageView* icon_view_ = nullptr; - views::View* bottom_view_ = nullptr; - views::View* image_container_ = nullptr; - ProportionalImageView* image_view_ = nullptr; - views::ProgressBar* progress_bar_view_ = nullptr; - std::vector<NotificationButton*> action_buttons_; - std::vector<views::View*> separators_; - std::unique_ptr<views::ImageView> small_image_view_; - NotificationControlButtonsView* control_buttons_view_; - - // Counter for view layouting, which is used during the CreateOrUpdate* - // phases to keep track of the view ordering. See crbug.com/901045 - int top_view_count_; - - DISALLOW_COPY_AND_ASSIGN(NotificationView); -}; - -} // namespace message_center - -#endif // UI_MESSAGE_CENTER_VIEWS_NOTIFICATION_VIEW_H_ diff --git a/chromium/ui/message_center/views/notification_view_md.cc b/chromium/ui/message_center/views/notification_view_md.cc index 5349bc34e5b..e5d6498e859 100644 --- a/chromium/ui/message_center/views/notification_view_md.cc +++ b/chromium/ui/message_center/views/notification_view_md.cc @@ -29,7 +29,6 @@ #include "ui/message_center/public/cpp/notification.h" #include "ui/message_center/public/cpp/notification_types.h" #include "ui/message_center/vector_icons.h" -#include "ui/message_center/views/bounded_label.h" #include "ui/message_center/views/notification_background_painter.h" #include "ui/message_center/views/notification_control_buttons_view.h" #include "ui/message_center/views/notification_header_view.h" @@ -69,7 +68,7 @@ constexpr gfx::Size kActionButtonMinSize(0, 32); // TODO(tetsui): Move |kIconViewSize| to public/cpp/message_center_constants.h // and merge with contradicting |kNotificationIconSize|. constexpr gfx::Size kIconViewSize(36, 36); -constexpr gfx::Insets kLargeImageContainerPadding(0, 12, 12, 12); +constexpr gfx::Insets kLargeImageContainerPadding(0, 16, 16, 16); constexpr gfx::Size kLargeImageMinSize(328, 0); constexpr gfx::Size kLargeImageMaxSize(328, 218); constexpr gfx::Insets kLeftContentPadding(2, 4, 0, 4); @@ -103,6 +102,8 @@ constexpr SkColor kTextfieldPlaceholderIconColorMD = // The icon size of inline reply input field. constexpr int kInputReplyButtonSize = 20; +// Max number of lines for title_view_. +constexpr int kMaxLinesForTitleView = 1; // Max number of lines for message_view_. constexpr int kMaxLinesForMessageView = 1; constexpr int kMaxLinesForExpandedMessageView = 4; @@ -136,6 +137,9 @@ constexpr int kTextFontSizeDelta = 1; // the ratio of the message width is limited to this value. constexpr double kProgressNotificationMessageRatio = 0.7; +// Line height of title and message views. +constexpr int kLineHeightMD = 17; + // This key/property allows tagging the textfield with its index. DEFINE_UI_CLASS_PROPERTY_KEY(int, kTextfieldIndexKey, 0U) @@ -382,19 +386,21 @@ NotificationInputContainerMD::NotificationInputContainerMD( layout->SetFlexForView(textfield_, 1); button_->SetBorder(views::CreateEmptyBorder(kInputReplyButtonPadding)); - button_->SetImageAlignment(views::ImageButton::ALIGN_CENTER, - views::ImageButton::ALIGN_MIDDLE); + button_->SetImageHorizontalAlignment(views::ImageButton::ALIGN_CENTER); + button_->SetImageVerticalAlignment(views::ImageButton::ALIGN_MIDDLE); OnAfterUserAction(textfield_); AddChildView(button_); } NotificationInputContainerMD::~NotificationInputContainerMD() = default; -void NotificationInputContainerMD::AnimateBackground( - const ui::LocatedEvent& event) { - if (View::HitTestPoint(event.location())) - AnimateInkDrop(views::InkDropState::ACTION_PENDING, - ui::LocatedEvent::FromIfValid(&event)); +void NotificationInputContainerMD::AnimateBackground(const ui::Event& event) { + // Try to get a located event. This can be NULL if triggered via keyboard. + const ui::LocatedEvent* located_event = ui::LocatedEvent::FromIfValid(&event); + // Use default animation if location is out of bounds. + if (located_event && !View::HitTestPoint(located_event->location())) + located_event = nullptr; + AnimateInkDrop(views::InkDropState::ACTION_PENDING, located_event); } void NotificationInputContainerMD::AddInkDropLayer(ui::Layer* ink_drop_layer) { @@ -534,7 +540,7 @@ NotificationViewMD::NotificationViewMD(const Notification& notification) content_row_->SetLayoutManager(std::make_unique<views::BoxLayout>( views::BoxLayout::kHorizontal, kContentRowPadding, 0)); content_row_layout->set_cross_axis_alignment( - views::BoxLayout::CROSS_AXIS_ALIGNMENT_START); + views::BoxLayout::CrossAxisAlignment::kStart); AddChildView(content_row_); // |left_content_| contains most contents like title, message, etc... @@ -599,7 +605,7 @@ void NotificationViewMD::Layout() { // The notification background is rounded in MessageView::Layout(), // but we also have to round the actions row background here. - if (actions_row_->visible()) { + if (actions_row_->GetVisible()) { constexpr SkScalar kCornerRadius = SkIntToScalar(kNotificationCornerRadius); // Use vertically larger clip path, so that actions row's top coners will @@ -659,7 +665,7 @@ void NotificationViewMD::OnMouseReleased(const ui::MouseEvent& event) { } // Ignore clicks of outside region when inline settings is shown. - if (settings_row_ && settings_row_->visible()) + if (settings_row_ && settings_row_->GetVisible()) return; MessageView::OnMouseReleased(event); @@ -704,7 +710,7 @@ void NotificationViewMD::UpdateControlButtonsVisibilityWithNotification( notification.should_show_settings_button()); control_buttons_view_->ShowSnoozeButton( notification.should_show_snooze_button()); - control_buttons_view_->ShowCloseButton(GetMode() == Mode::NORMAL); + control_buttons_view_->ShowCloseButton(GetMode() != Mode::PINNED); UpdateControlButtonsVisibility(); } @@ -713,7 +719,7 @@ void NotificationViewMD::ButtonPressed(views::Button* sender, // Tapping anywhere on |header_row_| can expand the notification, though only // |expand_button| can be focused by TAB. if (sender == header_row_) { - if (IsExpandable() && content_row_->visible()) { + if (IsExpandable() && content_row_->GetVisible()) { SetManuallyExpandedOrCollapsed(true); auto weak_ptr = weak_ptr_factory_.GetWeakPtr(); ToggleExpanded(); @@ -742,7 +748,7 @@ void NotificationViewMD::ButtonPressed(views::Button* sender, ? l10n_util::GetStringUTF16( IDS_MESSAGE_CENTER_NOTIFICATION_INLINE_REPLY_PLACEHOLDER) : *placeholder); - inline_reply_->AnimateBackground(*event.AsLocatedEvent()); + inline_reply_->AnimateBackground(event); inline_reply_->SetVisible(true); action_buttons_row_->SetVisible(false); // RequestFocus() should be called after SetVisible(). @@ -811,6 +817,13 @@ void NotificationViewMD::CreateOrUpdateTitleView( title_view_->SetFontList(font_list); title_view_->SetHorizontalAlignment(gfx::ALIGN_TO_HEAD); title_view_->SetEnabledColor(kRegularTextColorMD); + title_view_->SetLineHeight(kLineHeightMD); + // TODO(knollr): multiline should not be required, but we need to set the + // width of |title_view_| (because of crbug.com/682266), which only works in + // multiline mode. + title_view_->SetMultiLine(true); + title_view_->SetMaxLines(kMaxLinesForTitleView); + title_view_->SetAllowCharacterBreak(true); left_content_->AddChildViewAt(title_view_, left_content_count_); } else { title_view_->SetText(title); @@ -832,13 +845,17 @@ void NotificationViewMD::CreateOrUpdateMessageView( base::string16 text = gfx::TruncateString( notification.message(), kMessageCharacterLimitMD, gfx::WORD_BREAK); - const gfx::FontList& font_list = GetTextFontList(); - if (!message_view_) { - message_view_ = new BoundedLabel(text, font_list); - message_view_->SetLineLimit(kMaxLinesForMessageView); - message_view_->SetColor(kDimTextColorMD); + const gfx::FontList& font_list = GetTextFontList(); + message_view_ = new views::Label(text); + message_view_->SetFontList(font_list); + message_view_->SetHorizontalAlignment(gfx::ALIGN_TO_HEAD); + message_view_->SetEnabledColor(kDimTextColorMD); + message_view_->SetLineHeight(kLineHeightMD); + message_view_->SetMultiLine(true); + message_view_->SetMaxLines(kMaxLinesForMessageView); + message_view_->SetAllowCharacterBreak(true); left_content_->AddChildViewAt(message_view_, left_content_count_); } else { message_view_->SetText(text); @@ -1015,7 +1032,7 @@ void NotificationViewMD::CreateOrUpdateImageView( AddChildViewAt(image_container_view_, GetIndexOf(content_row_) + 1); } - static_cast<LargeImageView*>(image_container_view_->child_at(0)) + static_cast<LargeImageView*>(image_container_view_->children().front()) ->SetImage(notification.image().AsImageSkia()); } @@ -1034,7 +1051,7 @@ void NotificationViewMD::CreateOrUpdateActionButtonViews( DCHECK_EQ(this, actions_row_->parent()); // Hide inline reply field if it doesn't exist anymore. - if (inline_reply_->visible()) { + if (inline_reply_->GetVisible()) { const size_t index = inline_reply_->textfield()->GetProperty(kTextfieldIndexKey); if (index >= buttons.size() || !buttons[index].placeholder.has_value()) { @@ -1139,7 +1156,7 @@ void NotificationViewMD::CreateOrUpdateInlineSettingsViews( auto settings_button_layout = std::make_unique<views::BoxLayout>( views::BoxLayout::kHorizontal, kSettingsButtonRowPadding, 0); settings_button_layout->set_main_axis_alignment( - views::BoxLayout::MAIN_AXIS_ALIGNMENT_END); + views::BoxLayout::MainAxisAlignment::kEnd); settings_button_row->SetLayoutManager(std::move(settings_button_layout)); settings_button_row->AddChildView(settings_done_button_); settings_row_->AddChildView(settings_button_row); @@ -1148,9 +1165,13 @@ void NotificationViewMD::CreateOrUpdateInlineSettingsViews( } bool NotificationViewMD::IsExpandable() { + // Inline settings can not be expanded. + if (GetMode() == Mode::SETTING) + return false; + // Expandable if the message exceeds one line. - if (message_view_ && message_view_->visible() && - message_view_->GetLinesForWidthAndLimit(message_view_->width(), -1) > 1) { + if (message_view_ && message_view_->GetVisible() && + message_view_->GetRequiredLines() > 1) { return true; } // Expandable if there is at least one inline action. @@ -1177,8 +1198,8 @@ void NotificationViewMD::ToggleExpanded() { void NotificationViewMD::UpdateViewForExpandedState(bool expanded) { header_row_->SetExpanded(expanded); if (message_view_) { - message_view_->SetLineLimit(expanded ? kMaxLinesForExpandedMessageView - : kMaxLinesForMessageView); + message_view_->SetMaxLines(expanded ? kMaxLinesForExpandedMessageView + : kMaxLinesForMessageView); } if (image_container_view_) image_container_view_->SetVisible(expanded); @@ -1201,7 +1222,7 @@ void NotificationViewMD::UpdateViewForExpandedState(bool expanded) { right_content_->SetVisible(icon_view_ && (!hide_icon_on_expanded_ || !expanded)); - if (right_content_->visible()) { + if (right_content_->GetVisible()) { left_content_->SetBorder( views::CreateEmptyBorder(kLeftContentPaddingWithIcon)); @@ -1210,10 +1231,14 @@ void NotificationViewMD::UpdateViewForExpandedState(bool expanded) { // Ideally, we should fix the original bug, but it seems there's no obvious // solution for the bug according to https://crbug.com/678337#c7, we should // ensure that the change won't break any of the users of BoxLayout class. + if (title_view_) + title_view_->SizeToFit(kMessageViewWidthWithIcon); if (message_view_) message_view_->SizeToFit(kMessageViewWidthWithIcon); } else { left_content_->SetBorder(views::CreateEmptyBorder(kLeftContentPadding)); + if (title_view_) + title_view_->SizeToFit(kMessageViewWidth); if (message_view_) message_view_->SizeToFit(kMessageViewWidth); } @@ -1223,12 +1248,14 @@ void NotificationViewMD::UpdateViewForExpandedState(bool expanded) { void NotificationViewMD::ToggleInlineSettings(const ui::Event& event) { if (!settings_row_) return; - bool inline_settings_visible = !settings_row_->visible(); + + bool inline_settings_visible = !settings_row_->GetVisible(); bool disable_notification = - settings_row_->visible() && block_all_button_->checked(); + settings_row_->GetVisible() && block_all_button_->GetChecked(); settings_row_->SetVisible(inline_settings_visible); content_row_->SetVisible(!inline_settings_visible); + header_row_->SetTimestampVisible(!inline_settings_visible); // Always check "Don't block" when inline settings is shown. // If it's already blocked, users should not see inline settings. @@ -1324,14 +1351,17 @@ void NotificationViewMD::AddBackgroundAnimation(const ui::Event& event) { const gfx::Point& location = event.AsLocatedEvent()->location(); gfx::Point converted_location(location); View::ConvertPointToTarget(target, this, &converted_location); + + // Use default animation if location is out of bounds. + if (!View::HitTestPoint(converted_location)) { + AnimateInkDrop(views::InkDropState::ACTION_PENDING, nullptr); + return; + } + std::unique_ptr<ui::Event> cloned_event = ui::Event::Clone(event); ui::LocatedEvent* cloned_located_event = cloned_event->AsLocatedEvent(); cloned_located_event->set_location(converted_location); - - if (View::HitTestPoint(event.AsLocatedEvent()->location())) { - AnimateInkDrop(views::InkDropState::ACTION_PENDING, - ui::LocatedEvent::FromIfValid(cloned_located_event)); - } + AnimateInkDrop(views::InkDropState::ACTION_PENDING, cloned_located_event); } void NotificationViewMD::RemoveBackgroundAnimation() { diff --git a/chromium/ui/message_center/views/notification_view_md.h b/chromium/ui/message_center/views/notification_view_md.h index ef732236360..45e199e6723 100644 --- a/chromium/ui/message_center/views/notification_view_md.h +++ b/chromium/ui/message_center/views/notification_view_md.h @@ -29,7 +29,6 @@ class Textfield; namespace message_center { -class BoundedLabel; class NotificationHeaderView; class ProportionalImageView; @@ -123,7 +122,7 @@ class NotificationInputContainerMD : public views::InkDropHostView, NotificationInputContainerMD(NotificationInputDelegate* delegate); ~NotificationInputContainerMD() override; - void AnimateBackground(const ui::LocatedEvent& event); + void AnimateBackground(const ui::Event& event); // Overridden from views::InkDropHostView: void AddInkDropLayer(ui::Layer* ink_drop_layer) override; @@ -224,10 +223,14 @@ class MESSAGE_CENTER_EXPORT NotificationViewMD FRIEND_TEST_ALL_PREFIXES(NotificationViewMDTest, TestIconSizing); FRIEND_TEST_ALL_PREFIXES(NotificationViewMDTest, TestInlineReply); FRIEND_TEST_ALL_PREFIXES(NotificationViewMDTest, + TestInlineReplyActivateWithKeyPress); + FRIEND_TEST_ALL_PREFIXES(NotificationViewMDTest, TestInlineReplyRemovedByUpdate); + FRIEND_TEST_ALL_PREFIXES(NotificationViewMDTest, TestLongTitleAndMessage); FRIEND_TEST_ALL_PREFIXES(NotificationViewMDTest, UpdateAddingIcon); FRIEND_TEST_ALL_PREFIXES(NotificationViewMDTest, UpdateButtonCountTest); FRIEND_TEST_ALL_PREFIXES(NotificationViewMDTest, UpdateButtonsStateTest); + FRIEND_TEST_ALL_PREFIXES(NotificationViewMDTest, UpdateInSettings); FRIEND_TEST_ALL_PREFIXES(NotificationViewMDTest, UpdateViewsOrderingTest); FRIEND_TEST_ALL_PREFIXES(NotificationViewMDTest, UseImageAsIcon); @@ -301,7 +304,7 @@ class MESSAGE_CENTER_EXPORT NotificationViewMD // Views which are dynamically created inside view hierarchy. views::Label* title_view_ = nullptr; - BoundedLabel* message_view_ = nullptr; + views::Label* message_view_ = nullptr; views::Label* status_view_ = nullptr; ProportionalImageView* icon_view_ = nullptr; views::View* image_container_view_ = nullptr; diff --git a/chromium/ui/message_center/views/notification_view_md_unittest.cc b/chromium/ui/message_center/views/notification_view_md_unittest.cc index 37baaff9219..7054701a390 100644 --- a/chromium/ui/message_center/views/notification_view_md_unittest.cc +++ b/chromium/ui/message_center/views/notification_view_md_unittest.cc @@ -18,7 +18,6 @@ #include "ui/message_center/message_center.h" #include "ui/message_center/message_center_observer.h" #include "ui/message_center/public/cpp/message_center_constants.h" -#include "ui/message_center/views/bounded_label.h" #include "ui/message_center/views/notification_control_buttons_view.h" #include "ui/message_center/views/notification_header_view.h" #include "ui/message_center/views/padded_button.h" @@ -484,7 +483,7 @@ TEST_F(NotificationViewMDTest, UpdateButtonsStateTest) { EXPECT_FALSE(notification_view()->expanded_); notification->set_buttons(CreateButtons(2)); notification_view()->CreateOrUpdateViews(*notification); - EXPECT_FALSE(notification_view()->actions_row_->visible()); + EXPECT_FALSE(notification_view()->actions_row_->GetVisible()); // Adding buttons when expanded makes action buttons visible. // Reset back to zero buttons first. @@ -495,7 +494,7 @@ TEST_F(NotificationViewMDTest, UpdateButtonsStateTest) { EXPECT_TRUE(notification_view()->expanded_); notification->set_buttons(CreateButtons(2)); notification_view()->CreateOrUpdateViews(*notification); - EXPECT_TRUE(notification_view()->actions_row_->visible()); + EXPECT_TRUE(notification_view()->actions_row_->GetVisible()); EXPECT_EQ(views::Button::STATE_NORMAL, notification_view()->action_buttons_[0]->state()); @@ -537,7 +536,7 @@ TEST_F(NotificationViewMDTest, UpdateButtonCountTest) { // Action buttons are hidden by collapsed state. if (!notification_view()->expanded_) notification_view()->ToggleExpanded(); - EXPECT_TRUE(notification_view()->actions_row_->visible()); + EXPECT_TRUE(notification_view()->actions_row_->GetVisible()); EXPECT_EQ(views::Button::STATE_NORMAL, notification_view()->action_buttons_[0]->state()); @@ -589,7 +588,7 @@ TEST_F(NotificationViewMDTest, TestActionButtonClick) { // Action buttons are hidden by collapsed state. if (!notification_view()->expanded_) notification_view()->ToggleExpanded(); - EXPECT_TRUE(notification_view()->actions_row_->visible()); + EXPECT_TRUE(notification_view()->actions_row_->GetVisible()); // Now construct a mouse click event 1 pixel inside the boundary of the action // button. @@ -617,7 +616,7 @@ TEST_F(NotificationViewMDTest, TestInlineReply) { // Action buttons are hidden by collapsed state. if (!notification_view()->expanded_) notification_view()->ToggleExpanded(); - EXPECT_TRUE(notification_view()->actions_row_->visible()); + EXPECT_TRUE(notification_view()->actions_row_->GetVisible()); // Now construct a mouse click event 1 pixel inside the boundary of the action // button. @@ -631,15 +630,15 @@ TEST_F(NotificationViewMDTest, TestInlineReply) { EXPECT_EQ(-1, delegate_->clicked_button_index()); // Toggling should hide the inline textfield. - EXPECT_TRUE(notification_view()->inline_reply_->visible()); + EXPECT_TRUE(notification_view()->inline_reply_->GetVisible()); notification_view()->ToggleExpanded(); notification_view()->ToggleExpanded(); - EXPECT_FALSE(notification_view()->inline_reply_->visible()); + EXPECT_FALSE(notification_view()->inline_reply_->GetVisible()); // Click the button again and the inline textfield should be focused. generator.ClickLeftButton(); - EXPECT_TRUE(notification_view()->inline_reply_->visible()); - EXPECT_TRUE(notification_view()->inline_reply_->textfield()->visible()); + EXPECT_TRUE(notification_view()->inline_reply_->GetVisible()); + EXPECT_TRUE(notification_view()->inline_reply_->textfield()->GetVisible()); EXPECT_TRUE(notification_view()->inline_reply_->textfield()->HasFocus()); // Type the text. @@ -704,7 +703,7 @@ TEST_F(NotificationViewMDTest, TestInlineReplyRemovedByUpdate) { // Action buttons are hidden by collapsed state. if (!notification_view()->expanded_) notification_view()->ToggleExpanded(); - EXPECT_TRUE(notification_view()->actions_row_->visible()); + EXPECT_TRUE(notification_view()->actions_row_->GetVisible()); // Now construct a mouse click event 1 pixel inside the boundary of the action // button. @@ -717,15 +716,15 @@ TEST_F(NotificationViewMDTest, TestInlineReplyRemovedByUpdate) { // Nothing should be submitted at this point. EXPECT_EQ(-1, delegate_->clicked_button_index()); - EXPECT_TRUE(notification_view()->inline_reply_->visible()); - EXPECT_FALSE(notification_view()->action_buttons_row_->visible()); + EXPECT_TRUE(notification_view()->inline_reply_->GetVisible()); + EXPECT_FALSE(notification_view()->action_buttons_row_->GetVisible()); buttons[1].placeholder = base::nullopt; notification->set_buttons(buttons); UpdateNotificationViews(*notification); - EXPECT_FALSE(notification_view()->inline_reply_->visible()); - EXPECT_TRUE(notification_view()->action_buttons_row_->visible()); + EXPECT_FALSE(notification_view()->inline_reply_->GetVisible()); + EXPECT_TRUE(notification_view()->action_buttons_row_->GetVisible()); // Now it emits click event. delegate_->set_expecting_button_click(true); @@ -736,7 +735,31 @@ TEST_F(NotificationViewMDTest, TestInlineReplyRemovedByUpdate) { notification->set_buttons(buttons); UpdateNotificationViews(*notification); - EXPECT_FALSE(notification_view()->actions_row_->visible()); + EXPECT_FALSE(notification_view()->actions_row_->GetVisible()); +} + +TEST_F(NotificationViewMDTest, TestInlineReplyActivateWithKeyPress) { + std::unique_ptr<Notification> notification = CreateSimpleNotification(); + + std::vector<ButtonInfo> buttons = CreateButtons(2); + buttons[1].placeholder = base::string16(); + notification->set_buttons(buttons); + UpdateNotificationViews(*notification); + widget()->Show(); + + // Action buttons are hidden by collapsed state. + if (!notification_view()->expanded_) + notification_view()->ToggleExpanded(); + + ui::test::EventGenerator generator(GetRootWindow(widget())); + + // Press and release space key to open inline reply text field. + // Note: VKEY_RETURN should work too, but triggers a click on MacOS. + notification_view()->action_buttons_[1]->RequestFocus(); + generator.PressKey(ui::VKEY_SPACE, ui::EF_NONE); + generator.ReleaseKey(ui::VKEY_SPACE, ui::EF_NONE); + + EXPECT_TRUE(notification_view()->inline_reply_->GetVisible()); } // Synthetic scroll events are not supported on Mac in the views @@ -849,7 +872,7 @@ TEST_F(NotificationViewMDTest, Pinned) { // Visible at the initial state. EXPECT_TRUE(GetCloseButton()); - EXPECT_TRUE(GetCloseButton()->visible()); + EXPECT_TRUE(GetCloseButton()->GetVisible()); // Pin. notification->set_pinned(true); @@ -860,7 +883,7 @@ TEST_F(NotificationViewMDTest, Pinned) { notification->set_pinned(false); UpdateNotificationViews(*notification); EXPECT_TRUE(GetCloseButton()); - EXPECT_TRUE(GetCloseButton()->visible()); + EXPECT_TRUE(GetCloseButton()->GetVisible()); // Pin again. notification->set_pinned(true); @@ -969,7 +992,7 @@ TEST_F(NotificationViewMDTest, TestAccentColor) { // Action buttons are hidden by collapsed state. if (!notification_view()->expanded_) notification_view()->ToggleExpanded(); - EXPECT_TRUE(notification_view()->actions_row_->visible()); + EXPECT_TRUE(notification_view()->actions_row_->GetVisible()); // By default, header does not have accent color (default grey), and // buttons have default accent color. @@ -1008,14 +1031,14 @@ TEST_F(NotificationViewMDTest, UseImageAsIcon) { // Test normal notification. UpdateNotificationViews(*notification); EXPECT_FALSE(notification_view()->expanded_); - EXPECT_TRUE(notification_view()->icon_view_->visible()); - EXPECT_TRUE(notification_view()->right_content_->visible()); + EXPECT_TRUE(notification_view()->icon_view_->GetVisible()); + EXPECT_TRUE(notification_view()->right_content_->GetVisible()); // Icon on the right side is still visible when expanded. notification_view()->ToggleExpanded(); EXPECT_TRUE(notification_view()->expanded_); - EXPECT_TRUE(notification_view()->icon_view_->visible()); - EXPECT_TRUE(notification_view()->right_content_->visible()); + EXPECT_TRUE(notification_view()->icon_view_->GetVisible()); + EXPECT_TRUE(notification_view()->right_content_->GetVisible()); notification_view()->ToggleExpanded(); EXPECT_FALSE(notification_view()->expanded_); @@ -1023,14 +1046,14 @@ TEST_F(NotificationViewMDTest, UseImageAsIcon) { // Test notification with |use_image_for_icon| e.g. screenshot preview. notification->set_icon(gfx::Image()); UpdateNotificationViews(*notification); - EXPECT_TRUE(notification_view()->icon_view_->visible()); - EXPECT_TRUE(notification_view()->right_content_->visible()); + EXPECT_TRUE(notification_view()->icon_view_->GetVisible()); + EXPECT_TRUE(notification_view()->right_content_->GetVisible()); // Icon on the right side is not visible when expanded. notification_view()->ToggleExpanded(); EXPECT_TRUE(notification_view()->expanded_); - EXPECT_TRUE(notification_view()->icon_view_->visible()); - EXPECT_FALSE(notification_view()->right_content_->visible()); + EXPECT_TRUE(notification_view()->icon_view_->GetVisible()); + EXPECT_FALSE(notification_view()->right_content_->GetVisible()); } TEST_F(NotificationViewMDTest, NotificationWithoutIcon) { @@ -1041,12 +1064,12 @@ TEST_F(NotificationViewMDTest, NotificationWithoutIcon) { // If the notification has no icon, |icon_view_| shouldn't be created. EXPECT_FALSE(notification_view()->icon_view_); - EXPECT_FALSE(notification_view()->right_content_->visible()); + EXPECT_FALSE(notification_view()->right_content_->GetVisible()); // Toggling should not affect the icon. notification_view()->ToggleExpanded(); EXPECT_FALSE(notification_view()->icon_view_); - EXPECT_FALSE(notification_view()->right_content_->visible()); + EXPECT_FALSE(notification_view()->right_content_->GetVisible()); } TEST_F(NotificationViewMDTest, UpdateAddingIcon) { @@ -1067,13 +1090,40 @@ TEST_F(NotificationViewMDTest, UpdateAddingIcon) { UpdateNotificationViews(*notification); // Notification should now have an icon. - EXPECT_TRUE(notification_view()->icon_view_->visible()); - EXPECT_TRUE(notification_view()->right_content_->visible()); + EXPECT_TRUE(notification_view()->icon_view_->GetVisible()); + EXPECT_TRUE(notification_view()->right_content_->GetVisible()); // There should be some space now to show the icon. EXPECT_LT(notification_view()->left_content_->width(), left_content_width); } +TEST_F(NotificationViewMDTest, UpdateInSettings) { + std::unique_ptr<Notification> notification = CreateSimpleNotification(); + notification->set_type(NOTIFICATION_TYPE_SIMPLE); + UpdateNotificationViews(*notification); + + ui::test::EventGenerator generator(GetRootWindow(widget())); + + // Inline settings will be shown by clicking settings button. + EXPECT_FALSE(notification_view()->settings_row_->GetVisible()); + gfx::Point settings_cursor_location(1, 1); + views::View::ConvertPointToTarget( + notification_view()->control_buttons_view_->settings_button(), + notification_view(), &settings_cursor_location); + generator.MoveMouseTo(settings_cursor_location); + generator.ClickLeftButton(); + EXPECT_TRUE(notification_view()->settings_row_->GetVisible()); + + // Trigger an update event. + UpdateNotificationViews(*notification); + + // The close button should be visible. + views::Button* close_button = + notification_view()->control_buttons_view_->close_button(); + ASSERT_NE(nullptr, close_button); + EXPECT_TRUE(close_button->GetVisible()); +} + TEST_F(NotificationViewMDTest, InlineSettings) { std::unique_ptr<Notification> notification = CreateSimpleNotification(); notification->set_type(NOTIFICATION_TYPE_SIMPLE); @@ -1082,24 +1132,24 @@ TEST_F(NotificationViewMDTest, InlineSettings) { ui::test::EventGenerator generator(GetRootWindow(widget())); // Inline settings will be shown by clicking settings button. - EXPECT_FALSE(notification_view()->settings_row_->visible()); + EXPECT_FALSE(notification_view()->settings_row_->GetVisible()); gfx::Point settings_cursor_location(1, 1); views::View::ConvertPointToTarget( notification_view()->control_buttons_view_->settings_button(), notification_view(), &settings_cursor_location); generator.MoveMouseTo(settings_cursor_location); generator.ClickLeftButton(); - EXPECT_TRUE(notification_view()->settings_row_->visible()); + EXPECT_TRUE(notification_view()->settings_row_->GetVisible()); #if !defined(OS_CHROMEOS) // By clicking settings button again, it will toggle. Skip this on ChromeOS as // the control_buttons_view gets hidden when the inline settings are shown. generator.ClickLeftButton(); - EXPECT_FALSE(notification_view()->settings_row_->visible()); + EXPECT_FALSE(notification_view()->settings_row_->GetVisible()); // Show inline settings again. generator.ClickLeftButton(); - EXPECT_TRUE(notification_view()->settings_row_->visible()); + EXPECT_TRUE(notification_view()->settings_row_->GetVisible()); #endif // Construct a mouse click event 1 pixel inside the done button. @@ -1110,12 +1160,12 @@ TEST_F(NotificationViewMDTest, InlineSettings) { generator.ClickLeftButton(); // Just clicking Done button should not change the setting. - EXPECT_FALSE(notification_view()->settings_row_->visible()); + EXPECT_FALSE(notification_view()->settings_row_->GetVisible()); EXPECT_FALSE(delegate_->disable_notification_called()); generator.MoveMouseTo(settings_cursor_location); generator.ClickLeftButton(); - EXPECT_TRUE(notification_view()->settings_row_->visible()); + EXPECT_TRUE(notification_view()->settings_row_->GetVisible()); // Construct a mouse click event 1 pixel inside the block all button. gfx::Point block_cursor_location(1, 1); @@ -1127,7 +1177,7 @@ TEST_F(NotificationViewMDTest, InlineSettings) { generator.MoveMouseTo(done_cursor_location); generator.ClickLeftButton(); - EXPECT_FALSE(notification_view()->settings_row_->visible()); + EXPECT_FALSE(notification_view()->settings_row_->GetVisible()); EXPECT_TRUE(delegate_->disable_notification_called()); } @@ -1141,14 +1191,14 @@ TEST_F(NotificationViewMDTest, InlineSettingsInkDropAnimation) { ui::test::EventGenerator generator(GetRootWindow(widget())); // Inline settings will be shown by clicking settings button. - EXPECT_FALSE(notification_view()->settings_row_->visible()); + EXPECT_FALSE(notification_view()->settings_row_->GetVisible()); gfx::Point settings_cursor_location(1, 1); views::View::ConvertPointToTarget( notification_view()->control_buttons_view_->settings_button(), notification_view(), &settings_cursor_location); generator.MoveMouseTo(settings_cursor_location); generator.ClickLeftButton(); - EXPECT_TRUE(notification_view()->settings_row_->visible()); + EXPECT_TRUE(notification_view()->settings_row_->GetVisible()); notification_view()->GetInkDrop()->AddObserver(this); @@ -1176,7 +1226,7 @@ TEST_F(NotificationViewMDTest, TestClick) { // Collapse the notification if it's expanded. if (notification_view()->expanded_) notification_view()->ToggleExpanded(); - EXPECT_FALSE(notification_view()->actions_row_->visible()); + EXPECT_FALSE(notification_view()->actions_row_->GetVisible()); // Now construct a mouse click event 2 pixel inside from the bottom. gfx::Point cursor_location(notification_view()->size().width() / 2, @@ -1199,7 +1249,7 @@ TEST_F(NotificationViewMDTest, TestClickExpanded) { // Expand the notification if it's collapsed. if (!notification_view()->expanded_) notification_view()->ToggleExpanded(); - EXPECT_FALSE(notification_view()->actions_row_->visible()); + EXPECT_FALSE(notification_view()->actions_row_->GetVisible()); // Now construct a mouse click event 2 pixel inside from the bottom. gfx::Point cursor_location(notification_view()->size().width() / 2, @@ -1242,4 +1292,28 @@ TEST_F(NotificationViewMDTest, TestDeleteOnDisableNotification) { DummyEvent()); } +TEST_F(NotificationViewMDTest, TestLongTitleAndMessage) { + std::unique_ptr<Notification> notification = CreateSimpleNotification(); + notification->set_type(NotificationType::NOTIFICATION_TYPE_SIMPLE); + notification->set_title(base::ASCIIToUTF16("title")); + notification->set_message(base::ASCIIToUTF16( + "consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore " + "et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud " + "exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat.")); + UpdateNotificationViews(*notification); + notification_view()->ToggleExpanded(); + + // Get the height of the message view with a short title. + const int message_height = notification_view()->message_view_->height(); + + notification->set_title(base::ASCIIToUTF16( + "consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore " + "et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud " + "exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat.")); + UpdateNotificationViews(*notification); + + // The height of the message view should stay the same with a long title. + EXPECT_EQ(message_height, notification_view()->message_view_->height()); +} + } // namespace message_center diff --git a/chromium/ui/message_center/views/notification_view_unittest.cc b/chromium/ui/message_center/views/notification_view_unittest.cc deleted file mode 100644 index c464eff269f..00000000000 --- a/chromium/ui/message_center/views/notification_view_unittest.cc +++ /dev/null @@ -1,853 +0,0 @@ -// Copyright 2014 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 "ui/message_center/views/notification_view.h" - -#include <memory> - -#include "base/macros.h" -#include "base/strings/string_util.h" -#include "base/strings/utf_string_conversions.h" -#include "build/build_config.h" -#include "testing/gtest/include/gtest/gtest.h" -#include "third_party/skia/include/core/SkBitmap.h" -#include "third_party/skia/include/core/SkCanvas.h" -#include "third_party/skia/include/core/SkColor.h" -#include "ui/compositor/scoped_animation_duration_scale_mode.h" -#include "ui/events/event_processor.h" -#include "ui/events/event_utils.h" -#include "ui/events/test/event_generator.h" -#include "ui/gfx/canvas.h" -#include "ui/gfx/geometry/rect.h" -#include "ui/gfx/geometry/size.h" -#include "ui/gfx/image/image.h" -#include "ui/gfx/text_utils.h" -#include "ui/message_center/message_center.h" -#include "ui/message_center/message_center_style.h" -#include "ui/message_center/notification_list.h" -#include "ui/message_center/public/cpp/message_center_constants.h" -#include "ui/message_center/public/cpp/notification.h" -#include "ui/message_center/public/cpp/notification_types.h" -#include "ui/message_center/views/bounded_label.h" -#include "ui/message_center/views/message_view_factory.h" -#include "ui/message_center/views/notification_button.h" -#include "ui/message_center/views/notification_control_buttons_view.h" -#include "ui/message_center/views/padded_button.h" -#include "ui/message_center/views/proportional_image_view.h" -#include "ui/views/controls/button/image_button.h" -#include "ui/views/controls/label.h" -#include "ui/views/layout/fill_layout.h" -#include "ui/views/test/views_test_base.h" -#include "ui/views/test/widget_test.h" -#include "ui/views/widget/widget_delegate.h" -#include "ui/views/widget/widget_utils.h" - -#if defined(OS_WIN) -#include "ui/base/win/shell.h" -#endif - -namespace message_center { - -/* Test fixture ***************************************************************/ - -class NotificationViewTest : public views::ViewsTestBase { - public: - NotificationViewTest(); - ~NotificationViewTest() override; - - void SetUp() override; - void TearDown() override; - - views::Widget* widget() { return notification_view_->GetWidget(); } - NotificationView* notification_view() const { - return notification_view_.get(); - } - Notification* notification() { return notification_.get(); } - RichNotificationData* data() { return data_.get(); } - - protected: - // Used to fill bitmaps returned by CreateBitmap(). - static const SkColor kBitmapColor = SK_ColorGREEN; - - const gfx::Image CreateTestImage(int width, int height) { - return gfx::Image::CreateFrom1xBitmap(CreateBitmap(width, height)); - } - - const SkBitmap CreateBitmap(int width, int height) { - SkBitmap bitmap; - bitmap.allocN32Pixels(width, height); - bitmap.eraseColor(kBitmapColor); - return bitmap; - } - - std::vector<ButtonInfo> CreateButtons(int number) { - ButtonInfo info(base::ASCIIToUTF16("Test button title.")); - info.icon = CreateTestImage(4, 4); - return std::vector<ButtonInfo>(number, info); - } - - // Paints |view| and returns the size that the original image (which must have - // been created by CreateBitmap()) was scaled to. - gfx::Size GetImagePaintSize(ProportionalImageView* view) { - CHECK(view); - if (view->bounds().IsEmpty()) - return gfx::Size(); - - gfx::Size canvas_size = view->bounds().size(); - gfx::Canvas canvas(canvas_size, 1.0 /* image_scale */, - true /* is_opaque */); - static_assert(kBitmapColor != SK_ColorBLACK, - "The bitmap color must match the background color"); - canvas.DrawColor(SK_ColorBLACK); - view->OnPaint(&canvas); - - SkBitmap bitmap = canvas.GetBitmap(); - // Incrementally inset each edge at its midpoint to find the bounds of the - // rect containing the image's color. This assumes that the image is - // centered in the canvas. - const int kHalfWidth = canvas_size.width() / 2; - const int kHalfHeight = canvas_size.height() / 2; - gfx::Rect rect(canvas_size); - while (rect.width() > 0 && - bitmap.getColor(rect.x(), kHalfHeight) != kBitmapColor) - rect.Inset(1, 0, 0, 0); - while (rect.height() > 0 && - bitmap.getColor(kHalfWidth, rect.y()) != kBitmapColor) - rect.Inset(0, 1, 0, 0); - while (rect.width() > 0 && - bitmap.getColor(rect.right() - 1, kHalfHeight) != kBitmapColor) - rect.Inset(0, 0, 1, 0); - while (rect.height() > 0 && - bitmap.getColor(kHalfWidth, rect.bottom() - 1) != kBitmapColor) - rect.Inset(0, 0, 0, 1); - - return rect.size(); - } - - void CheckVerticalOrderInNotification() { - std::vector<views::View*> vertical_order; - vertical_order.push_back(notification_view()->top_view_); - vertical_order.push_back(notification_view()->image_view_); - std::copy(notification_view()->action_buttons_.begin(), - notification_view()->action_buttons_.end(), - std::back_inserter(vertical_order)); - auto current = vertical_order.begin(); - auto last = current++; - while (current != vertical_order.end()) { - gfx::Point last_point = (*last)->origin(); - views::View::ConvertPointToTarget( - (*last), notification_view(), &last_point); - - gfx::Point current_point = (*current)->origin(); - views::View::ConvertPointToTarget( - (*current), notification_view(), ¤t_point); - - EXPECT_LT(last_point.y(), current_point.y()); - last = current++; - } - } - - views::Button* GetCloseButton() { - return notification_view()->control_buttons_view_->close_button(); - } - - views::Button* GetSettingsButton() { - return notification_view()->control_buttons_view_->settings_button(); - } - - void UpdateNotificationViews() { - MessageCenter::Get()->AddNotification( - std::make_unique<Notification>(*notification())); - notification_view()->UpdateWithNotification(*notification()); - } - - float GetNotificationSlideAmount() const { - return notification_view_->GetSlideOutLayer() - ->transform() - .To2dTranslation() - .x(); - } - - int GetTitleWidth() { - return notification_view()->title_view_->GetContentsBounds().width(); - } - - int GetTitleHeight() { - return notification_view()->title_view_->GetContentsBounds().height(); - } - - int GetTitleCharactersPerLine(base::char16 character) { - int available_width = GetTitleWidth(); -#if !defined(OS_CHROMEOS) - // On non-ChromeOS systems, we expect the available width to be reduced by - // the width of the control buttons view. - available_width -= - notification_view()->control_buttons_view_->GetPreferredSize().width(); -#endif - const gfx::FontList& font_list = - notification_view()->title_view_->font_list(); - - // To get the number of characters that fit into one line of text with a - // given width, we first get the width of one character. - int char_width = - gfx::GetStringWidth(base::string16(1, character), font_list); - - // We then assume that multiple of these characters next to each other have - // a total width of N * char_width. This is usually a very good estimation, - // but based on the platform, it may vary due to font shaping. - int characters_per_line = available_width / char_width; - - // These while loops account for any unexpected font shaping and are not - // expected to be expensive. - while (gfx::GetStringWidth(base::string16(characters_per_line, character), - font_list) <= available_width) { - characters_per_line++; - } - while (gfx::GetStringWidth(base::string16(characters_per_line, character), - font_list) > available_width) { - characters_per_line--; - } - - return characters_per_line; - } - - bool IsRemovedAfterIdle(const std::string& notification_id) const { - base::RunLoop().RunUntilIdle(); - return !MessageCenter::Get()->FindVisibleNotificationById(notification_id); - } - - void RemoveNotificationView() { notification_view_.reset(); } - - void DispatchGesture(const ui::GestureEventDetails& details) { - ui::test::EventGenerator generator( - GetRootWindow(notification_view()->GetWidget())); - ui::GestureEvent event(0, 0, 0, ui::EventTimeForNow(), details); - generator.Dispatch(&event); - } - - void BeginScroll() { - DispatchGesture(ui::GestureEventDetails(ui::ET_GESTURE_SCROLL_BEGIN)); - } - - void EndScroll() { - DispatchGesture(ui::GestureEventDetails(ui::ET_GESTURE_SCROLL_END)); - } - - void ScrollBy(int dx) { - DispatchGesture( - ui::GestureEventDetails(ui::ET_GESTURE_SCROLL_UPDATE, dx, 0)); - } - - private: - std::unique_ptr<RichNotificationData> data_; - std::unique_ptr<Notification> notification_; - std::unique_ptr<NotificationView> notification_view_; - - DISALLOW_COPY_AND_ASSIGN(NotificationViewTest); -}; - -NotificationViewTest::NotificationViewTest() { -} - -NotificationViewTest::~NotificationViewTest() { -} - -void NotificationViewTest::SetUp() { - views::ViewsTestBase::SetUp(); - - MessageCenter::Initialize(); - - // Create a dummy notification. - SkBitmap bitmap; - data_.reset(new RichNotificationData()); - notification_.reset(new Notification( - NOTIFICATION_TYPE_BASE_FORMAT, std::string("notification id"), - base::UTF8ToUTF16("title"), base::UTF8ToUTF16("message"), - CreateTestImage(80, 80), base::UTF8ToUTF16("display source"), GURL(), - NotifierId(NotifierType::APPLICATION, "extension_id"), *data_, NULL)); - notification_->set_small_image(CreateTestImage(16, 16)); - notification_->set_image(CreateTestImage(320, 240)); - - // Then create a new NotificationView with that single notification. - notification_view_.reset(new NotificationView(*notification_)); - - // It depends on platform whether shadows are added. - // See MessageViewFactory::Create. - bool is_nested = true; -#if defined(OS_LINUX) - is_nested = false; -#endif -#if defined(OS_WIN) - if (!ui::win::IsAeroGlassEnabled()) - is_nested = false; -#endif - if (is_nested) - notification_view_->SetIsNested(); - - notification_view_->set_owned_by_client(); - - views::Widget::InitParams init_params( - CreateParams(views::Widget::InitParams::TYPE_POPUP)); - views::Widget* widget = new views::Widget(); - widget->Init(init_params); - widget->SetContentsView(notification_view_.get()); - widget->SetSize(notification_view_->GetPreferredSize()); - widget->Show(); -} - -void NotificationViewTest::TearDown() { - widget()->Close(); - notification_view_.reset(); - views::ViewsTestBase::TearDown(); - MessageCenter::Shutdown(); -} - -/* Unit tests *****************************************************************/ - -TEST_F(NotificationViewTest, CreateOrUpdateTest) { - EXPECT_TRUE(NULL != notification_view()->title_view_); - EXPECT_TRUE(NULL != notification_view()->message_view_); - EXPECT_TRUE(NULL != notification_view()->icon_view_); - EXPECT_TRUE(NULL != notification_view()->image_view_); - - notification()->set_image(gfx::Image()); - notification()->set_title(base::ASCIIToUTF16("")); - notification()->set_message(base::ASCIIToUTF16("")); - notification()->set_icon(gfx::Image()); - - notification_view()->UpdateWithNotification(*notification()); - EXPECT_TRUE(NULL == notification_view()->title_view_); - EXPECT_TRUE(NULL == notification_view()->message_view_); - EXPECT_TRUE(NULL == notification_view()->image_view_); - // Notification must have a control buttons view. - EXPECT_TRUE(NULL != notification_view()->control_buttons_view_); - // Notification is not pinned and have a close button by default. - EXPECT_TRUE(NULL != GetCloseButton()); - // Notification doesn't have a settings button by default. - EXPECT_TRUE(NULL == GetSettingsButton()); - // We still expect an icon view for all layouts. - EXPECT_TRUE(NULL != notification_view()->icon_view_); -} - -TEST_F(NotificationViewTest, UpdateViewsOrderingTest) { - EXPECT_NE(nullptr, notification_view()->title_view_); - EXPECT_NE(nullptr, notification_view()->message_view_); - EXPECT_EQ(0, notification_view()->top_view_->GetIndexOf( - notification_view()->title_view_)); - EXPECT_EQ(1, notification_view()->top_view_->GetIndexOf( - notification_view()->message_view_)); - - notification()->set_title(base::string16()); - - notification_view()->CreateOrUpdateViews(*notification()); - - EXPECT_EQ(nullptr, notification_view()->title_view_); - EXPECT_NE(nullptr, notification_view()->message_view_); - EXPECT_EQ(0, notification_view()->top_view_->GetIndexOf( - notification_view()->message_view_)); - - notification()->set_title(base::UTF8ToUTF16("title")); - - notification_view()->CreateOrUpdateViews(*notification()); - - EXPECT_NE(nullptr, notification_view()->title_view_); - EXPECT_NE(nullptr, notification_view()->message_view_); - EXPECT_EQ(0, notification_view()->top_view_->GetIndexOf( - notification_view()->title_view_)); - EXPECT_EQ(1, notification_view()->top_view_->GetIndexOf( - notification_view()->message_view_)); -} - -TEST_F(NotificationViewTest, CreateOrUpdateTestSettingsButton) { - data()->settings_button_handler = SettingsButtonHandler::INLINE; - Notification notification( - NOTIFICATION_TYPE_BASE_FORMAT, std::string("notification id"), - base::UTF8ToUTF16("title"), base::UTF8ToUTF16("message"), - CreateTestImage(80, 80), base::UTF8ToUTF16("display source"), - GURL("https://hello.com"), - NotifierId(NotifierType::APPLICATION, "extension_id"), *data(), nullptr); - - notification_view()->UpdateWithNotification(notification); - EXPECT_TRUE(NULL != notification_view()->title_view_); - EXPECT_TRUE(NULL != notification_view()->message_view_); - EXPECT_TRUE(NULL != notification_view()->context_message_view_); - EXPECT_TRUE(NULL != GetCloseButton()); - EXPECT_TRUE(NULL != GetSettingsButton()); - EXPECT_TRUE(NULL != notification_view()->icon_view_); - - EXPECT_TRUE(NULL == notification_view()->image_view_); -} - -TEST_F(NotificationViewTest, TestLineLimits) { - notification()->set_image(CreateTestImage(0, 0)); - notification()->set_context_message(base::ASCIIToUTF16("")); - notification_view()->UpdateWithNotification(*notification()); - - EXPECT_EQ(5, notification_view()->GetMessageLineLimit(0, 360)); - EXPECT_EQ(5, notification_view()->GetMessageLineLimit(1, 360)); - EXPECT_EQ(3, notification_view()->GetMessageLineLimit(2, 360)); - - notification()->set_image(CreateTestImage(2, 2)); - notification_view()->UpdateWithNotification(*notification()); - - EXPECT_EQ(5, notification_view()->GetMessageLineLimit(0, 360)); - EXPECT_EQ(5, notification_view()->GetMessageLineLimit(1, 360)); - EXPECT_EQ(3, notification_view()->GetMessageLineLimit(2, 360)); - - notification()->set_context_message(base::ASCIIToUTF16("foo")); - notification_view()->UpdateWithNotification(*notification()); - - EXPECT_TRUE(notification_view()->context_message_view_ != NULL); - - EXPECT_EQ(5, notification_view()->GetMessageLineLimit(0, 360)); - EXPECT_EQ(5, notification_view()->GetMessageLineLimit(1, 360)); - EXPECT_EQ(3, notification_view()->GetMessageLineLimit(2, 360)); -} - -TEST_F(NotificationViewTest, TestIconSizing) { - notification()->set_type(NOTIFICATION_TYPE_SIMPLE); - ProportionalImageView* view = notification_view()->icon_view_; - - // Icons smaller than the maximum size should remain unscaled. - notification()->set_icon(CreateTestImage(kNotificationIconSize / 2, - kNotificationIconSize / 4)); - UpdateNotificationViews(); - EXPECT_EQ(gfx::Size(kNotificationIconSize / 2, - kNotificationIconSize / 4).ToString(), - GetImagePaintSize(view).ToString()); - - // Icons of exactly the intended icon size should remain unscaled. - notification()->set_icon(CreateTestImage(kNotificationIconSize, - kNotificationIconSize)); - UpdateNotificationViews(); - EXPECT_EQ(gfx::Size(kNotificationIconSize, kNotificationIconSize).ToString(), - GetImagePaintSize(view).ToString()); - - // Icons over the maximum size should be scaled down, maintaining proportions. - notification()->set_icon(CreateTestImage(2 * kNotificationIconSize, - 2 * kNotificationIconSize)); - UpdateNotificationViews(); - EXPECT_EQ(gfx::Size(kNotificationIconSize, kNotificationIconSize).ToString(), - GetImagePaintSize(view).ToString()); - - notification()->set_icon(CreateTestImage(4 * kNotificationIconSize, - 2 * kNotificationIconSize)); - UpdateNotificationViews(); - EXPECT_EQ(gfx::Size(kNotificationIconSize, - kNotificationIconSize / 2).ToString(), - GetImagePaintSize(view).ToString()); -} - -TEST_F(NotificationViewTest, TestImageSizing) { - ProportionalImageView* view = notification_view()->image_view_; - const gfx::Size kIdealSize(kNotificationPreferredImageWidth, - kNotificationPreferredImageHeight); - - // Images should be scaled to the ideal size. - notification()->set_image(CreateTestImage(kIdealSize.width() / 2, - kIdealSize.height() / 2)); - UpdateNotificationViews(); - EXPECT_EQ(kIdealSize.ToString(), GetImagePaintSize(view).ToString()); - - notification()->set_image(CreateTestImage(kIdealSize.width(), - kIdealSize.height())); - UpdateNotificationViews(); - EXPECT_EQ(kIdealSize.ToString(), GetImagePaintSize(view).ToString()); - - notification()->set_image(CreateTestImage(kIdealSize.width() * 2, - kIdealSize.height() * 2)); - UpdateNotificationViews(); - EXPECT_EQ(kIdealSize.ToString(), GetImagePaintSize(view).ToString()); - - // Original aspect ratios should be preserved. - gfx::Size orig_size(kIdealSize.width() * 2, kIdealSize.height()); - notification()->set_image( - CreateTestImage(orig_size.width(), orig_size.height())); - UpdateNotificationViews(); - gfx::Size paint_size = GetImagePaintSize(view); - gfx::Size container_size = kIdealSize; - container_size.Enlarge(-2 * kNotificationImageBorderSize, - -2 * kNotificationImageBorderSize); - EXPECT_EQ(GetImageSizeForContainerSize(container_size, orig_size).ToString(), - paint_size.ToString()); - ASSERT_GT(paint_size.height(), 0); - EXPECT_EQ(orig_size.width() / orig_size.height(), - paint_size.width() / paint_size.height()); - - orig_size.SetSize(kIdealSize.width(), kIdealSize.height() * 2); - notification()->set_image( - CreateTestImage(orig_size.width(), orig_size.height())); - UpdateNotificationViews(); - paint_size = GetImagePaintSize(view); - EXPECT_EQ(GetImageSizeForContainerSize(container_size, orig_size).ToString(), - paint_size.ToString()); - ASSERT_GT(paint_size.height(), 0); - EXPECT_EQ(orig_size.width() / orig_size.height(), - paint_size.width() / paint_size.height()); -} - -TEST_F(NotificationViewTest, UpdateButtonsStateTest) { - notification()->set_buttons(CreateButtons(2)); - notification_view()->UpdateWithNotification(*notification()); - widget()->Show(); - - EXPECT_EQ(views::Button::STATE_NORMAL, - notification_view()->action_buttons_[0]->state()); - - // Now construct a mouse move event 1 pixel inside the boundary of the action - // button. - gfx::Point cursor_location(1, 1); - views::View::ConvertPointToWidget(notification_view()->action_buttons_[0], - &cursor_location); - ui::MouseEvent move(ui::ET_MOUSE_MOVED, cursor_location, cursor_location, - ui::EventTimeForNow(), ui::EF_NONE, ui::EF_NONE); - widget()->OnMouseEvent(&move); - - EXPECT_EQ(views::Button::STATE_HOVERED, - notification_view()->action_buttons_[0]->state()); - - notification_view()->UpdateWithNotification(*notification()); - - EXPECT_EQ(views::Button::STATE_HOVERED, - notification_view()->action_buttons_[0]->state()); - - // Now construct a mouse move event 1 pixel outside the boundary of the - // widget. - cursor_location = gfx::Point(-1, -1); - move = ui::MouseEvent(ui::ET_MOUSE_MOVED, cursor_location, cursor_location, - ui::EventTimeForNow(), ui::EF_NONE, ui::EF_NONE); - widget()->OnMouseEvent(&move); - - EXPECT_EQ(views::Button::STATE_NORMAL, - notification_view()->action_buttons_[0]->state()); -} - -TEST_F(NotificationViewTest, UpdateButtonCountTest) { - notification()->set_buttons(CreateButtons(2)); - notification_view()->UpdateWithNotification(*notification()); - widget()->Show(); - - EXPECT_EQ(views::Button::STATE_NORMAL, - notification_view()->action_buttons_[0]->state()); - EXPECT_EQ(views::Button::STATE_NORMAL, - notification_view()->action_buttons_[1]->state()); - - ui::test::EventGenerator generator( - GetRootWindow(notification_view()->GetWidget())); - - // Now construct a mouse move event 1 pixel inside the boundary of the action - // button. - gfx::Point cursor_location(1, 1); - views::View::ConvertPointToTarget(notification_view()->action_buttons_[0], - notification_view(), &cursor_location); - generator.MoveMouseTo(cursor_location); - - EXPECT_EQ(views::Button::STATE_HOVERED, - notification_view()->action_buttons_[0]->state()); - EXPECT_EQ(views::Button::STATE_NORMAL, - notification_view()->action_buttons_[1]->state()); - - notification()->set_buttons(CreateButtons(1)); - notification_view()->UpdateWithNotification(*notification()); - - EXPECT_EQ(views::Button::STATE_HOVERED, - notification_view()->action_buttons_[0]->state()); - EXPECT_EQ(1u, notification_view()->action_buttons_.size()); - - // Now construct a mouse move event 1 pixel outside the boundary of the - // widget. - cursor_location = gfx::Point(-1, -1); - views::View::ConvertPointToScreen(notification_view(), &cursor_location); - generator.MoveMouseTo(cursor_location); - - EXPECT_EQ(views::Button::STATE_NORMAL, - notification_view()->action_buttons_[0]->state()); -} - -TEST_F(NotificationViewTest, SettingsButtonTest) { - data()->settings_button_handler = SettingsButtonHandler::INLINE; - Notification notf( - NOTIFICATION_TYPE_BASE_FORMAT, std::string("notification id"), - base::UTF8ToUTF16("title"), base::UTF8ToUTF16("message"), - CreateTestImage(80, 80), base::UTF8ToUTF16("display source"), - GURL("https://hello.com"), - NotifierId(NotifierType::APPLICATION, "extension_id"), *data(), nullptr); - notification_view()->UpdateWithNotification(notf); - widget()->Show(); - - EXPECT_TRUE(NULL != GetSettingsButton()); - EXPECT_EQ(views::Button::STATE_NORMAL, GetSettingsButton()->state()); - - ui::test::EventGenerator generator(GetRootWindow(widget())); - - // Now construct a mouse move event 1 pixel inside the boundary of the action - // button. - gfx::Point cursor_location(1, 1); - views::View::ConvertPointToTarget(GetSettingsButton(), notification_view(), - &cursor_location); - generator.MoveMouseTo(cursor_location); - - EXPECT_EQ(views::Button::STATE_HOVERED, GetSettingsButton()->state()); - - // Now construct a mouse move event 1 pixel outside the boundary of the - // widget. - cursor_location = gfx::Point(-1, -1); - views::View::ConvertPointToTarget(GetSettingsButton(), notification_view(), - &cursor_location); - generator.MoveMouseTo(cursor_location); - - EXPECT_EQ(views::Button::STATE_NORMAL, GetSettingsButton()->state()); -} - -TEST_F(NotificationViewTest, ViewOrderingTest) { - // Tests that views are created in the correct vertical order. - notification()->set_buttons(CreateButtons(2)); - - // Layout the initial views. - UpdateNotificationViews(); - - // Double-check that vertical order is correct. - CheckVerticalOrderInNotification(); - - // Tests that views remain in that order even after an update. - UpdateNotificationViews(); - CheckVerticalOrderInNotification(); -} - -TEST_F(NotificationViewTest, TitleWrappingTest) { - data()->settings_button_handler = SettingsButtonHandler::INLINE; - Notification notf( - NOTIFICATION_TYPE_BASE_FORMAT, std::string("notification id"), - base::UTF8ToUTF16(""), base::UTF8ToUTF16("message"), - CreateTestImage(80, 80), base::UTF8ToUTF16("display source"), - GURL("https://hello.com"), - NotifierId(NotifierType::APPLICATION, "extension_id"), *data(), nullptr); - - const base::char16 character = '1'; - const int characters_per_line = GetTitleCharactersPerLine(character); - - // Test a very short title - notf.set_title(base::string16(1, character)); - notification_view()->UpdateWithNotification(notf); - int one_line_height = GetTitleHeight(); - - // Test a title that exactly fits into one line - notf.set_title(base::string16(characters_per_line, character)); - notification_view()->UpdateWithNotification(notf); - EXPECT_EQ(one_line_height, GetTitleHeight()); - - // Test a title that breaks into 2 lines with only 1 char in the second line - notf.set_title(base::string16(characters_per_line + 1, character)); - notification_view()->UpdateWithNotification(notf); - int two_line_height = GetTitleHeight(); - EXPECT_GT(two_line_height, one_line_height); - - // Test a title that clearly breaks into 2 lines - notf.set_title(base::string16(characters_per_line + 10, character)); - notification_view()->UpdateWithNotification(notf); - EXPECT_EQ(two_line_height, GetTitleHeight()); - - // Test a title that fits exactly into 2 lines - notf.set_title(base::string16(characters_per_line * 2, character)); - notification_view()->UpdateWithNotification(notf); - EXPECT_EQ(two_line_height, GetTitleHeight()); - - // Test a title that would break into 3 lines but has ellipsis in the 2nd line - notf.set_title(base::string16(characters_per_line * 2 + 1, character)); - notification_view()->UpdateWithNotification(notf); - EXPECT_EQ(two_line_height, GetTitleHeight()); -} - -TEST_F(NotificationViewTest, FormatContextMessageTest) { - const std::string kRegularContextText = "Context Text"; - const std::string kVeryLongContextText = - "VERY VERY VERY VERY VERY VERY VERY VERY VERY VERY VERY VERY" - "VERY VERY VERY VERY VERY VERY VERY VERY VERY VERY VERY VERY" - "VERY VERY VERY VERY Long Long Long Long Long Long Long Long context"; - - const std::string kVeryLongElidedContextText = - "VERY VERY VERY VERY VERY VERY VERY VERY VERY VERY VERY VERYVERY VERY " - "VERY VERY VERY VERY VERY VERY VERY VERY VERY\xE2\x80\xA6"; - - const std::string kChromeUrl = "chrome://settings"; - const std::string kUrlContext = "http://chromium.org/hello"; - const std::string kHostContext = "chromium.org"; - const std::string kLongUrlContext = - "https://" - "veryveryveryveryveyryveryveryveryveryveyryveryvery.veryveryveyrylong." - "chromium.org/hello"; - - Notification notification1(NOTIFICATION_TYPE_BASE_FORMAT, std::string(""), - base::UTF8ToUTF16(""), base::UTF8ToUTF16(""), - CreateTestImage(80, 80), base::UTF8ToUTF16(""), - GURL(), NotifierId(GURL()), *data(), NULL); - notification1.set_context_message(base::ASCIIToUTF16(kRegularContextText)); - - base::string16 result = - notification_view()->FormatContextMessage(notification1); - EXPECT_EQ(kRegularContextText, base::UTF16ToUTF8(result)); - - notification1.set_context_message(base::ASCIIToUTF16(kVeryLongContextText)); - result = notification_view()->FormatContextMessage(notification1); - EXPECT_EQ(kVeryLongElidedContextText, base::UTF16ToUTF8(result)); - - Notification notification2( - NOTIFICATION_TYPE_BASE_FORMAT, std::string(""), base::UTF8ToUTF16(""), - base::UTF8ToUTF16(""), CreateTestImage(80, 80), base::UTF8ToUTF16(""), - GURL(kUrlContext), NotifierId(GURL()), *data(), NULL); - notification2.set_context_message(base::ASCIIToUTF16("")); - - result = notification_view()->FormatContextMessage(notification2); - EXPECT_EQ(kHostContext, base::UTF16ToUTF8(result)); - - // Non http url and empty context message should yield an empty context - // message. - Notification notification3( - NOTIFICATION_TYPE_BASE_FORMAT, std::string(""), base::UTF8ToUTF16(""), - base::UTF8ToUTF16(""), CreateTestImage(80, 80), base::UTF8ToUTF16(""), - GURL(kChromeUrl), NotifierId(GURL()), *data(), NULL); - notification3.set_context_message(base::ASCIIToUTF16("")); - result = notification_view()->FormatContextMessage(notification3); - EXPECT_TRUE(result.empty()); - - // Long http url should be elided - Notification notification4( - NOTIFICATION_TYPE_BASE_FORMAT, std::string(""), base::UTF8ToUTF16(""), - base::UTF8ToUTF16(""), CreateTestImage(80, 80), base::UTF8ToUTF16(""), - GURL(kLongUrlContext), NotifierId(GURL()), *data(), NULL); - notification4.set_context_message(base::ASCIIToUTF16("")); - result = notification_view()->FormatContextMessage(notification4); - - // Different platforms elide at different lengths so we do - // some generic checking here. - // The url has been elided (it starts with an ellipsis) - // The end of the domainsuffix is shown - // the url piece is not shown - std::string result_utf8 = base::UTF16ToUTF8(result); - EXPECT_TRUE(result_utf8.find(".veryveryveyrylong.chromium.org") != - std::string::npos); - EXPECT_TRUE(base::StartsWith(result_utf8, "\xE2\x80\xA6", - base::CompareCase::SENSITIVE)); - EXPECT_TRUE(result_utf8.find("hello") == std::string::npos); -} - -// Synthetic scroll events are not supported on Mac in the views -// test framework. -#if defined(OS_MACOSX) -#define MAYBE_SlideOut DISABLED_SlideOut -#else -#define MAYBE_SlideOut SlideOut -#endif -TEST_F(NotificationViewTest, MAYBE_SlideOut) { - ui::ScopedAnimationDurationScaleMode zero_duration_scope( - ui::ScopedAnimationDurationScaleMode::ZERO_DURATION); - - UpdateNotificationViews(); - std::string notification_id = notification()->id(); - - BeginScroll(); - ScrollBy(-10); - EXPECT_FALSE(IsRemovedAfterIdle(notification_id)); - EXPECT_EQ(-10.f, GetNotificationSlideAmount()); - EndScroll(); - EXPECT_FALSE(IsRemovedAfterIdle(notification_id)); - EXPECT_EQ(0.f, GetNotificationSlideAmount()); - - BeginScroll(); - ScrollBy(-200); - EXPECT_FALSE(IsRemovedAfterIdle(notification_id)); - EXPECT_EQ(-200.f, GetNotificationSlideAmount()); - EndScroll(); - EXPECT_TRUE(IsRemovedAfterIdle(notification_id)); -} - -#if defined(OS_MACOSX) -#define MAYBE_SlideOutNested DISABLED_SlideOutNested -#else -#define MAYBE_SlideOutNested SlideOutNested -#endif -TEST_F(NotificationViewTest, MAYBE_SlideOutNested) { - ui::ScopedAnimationDurationScaleMode zero_duration_scope( - ui::ScopedAnimationDurationScaleMode::ZERO_DURATION); - - UpdateNotificationViews(); - std::string notification_id = notification()->id(); - - BeginScroll(); - ScrollBy(-10); - EXPECT_FALSE(IsRemovedAfterIdle(notification_id)); - EXPECT_EQ(-10.f, GetNotificationSlideAmount()); - EndScroll(); - EXPECT_FALSE(IsRemovedAfterIdle(notification_id)); - EXPECT_EQ(0.f, GetNotificationSlideAmount()); - - BeginScroll(); - ScrollBy(-200); - EXPECT_FALSE(IsRemovedAfterIdle(notification_id)); - EXPECT_EQ(-200.f, GetNotificationSlideAmount()); - EndScroll(); - EXPECT_TRUE(IsRemovedAfterIdle(notification_id)); -} - -// Pinning notification is ChromeOS only feature. -#if defined(OS_CHROMEOS) - -TEST_F(NotificationViewTest, SlideOutPinned) { - ui::ScopedAnimationDurationScaleMode zero_duration_scope( - ui::ScopedAnimationDurationScaleMode::ZERO_DURATION); - - notification()->set_pinned(true); - notification_view()->SetIsNested(); - UpdateNotificationViews(); - std::string notification_id = notification()->id(); - - BeginScroll(); - ScrollBy(-200); - EXPECT_FALSE(IsRemovedAfterIdle(notification_id)); - EXPECT_LT(-200.f, GetNotificationSlideAmount()); - EndScroll(); - EXPECT_FALSE(IsRemovedAfterIdle(notification_id)); -} - -TEST_F(NotificationViewTest, PopupsCantPin) { - ui::ScopedAnimationDurationScaleMode zero_duration_scope( - ui::ScopedAnimationDurationScaleMode::ZERO_DURATION); - - notification()->set_pinned(true); - UpdateNotificationViews(); - std::string notification_id = notification()->id(); - - auto shown_as_popup = [](const std::string& notification_id) { - auto notifications = MessageCenter::Get()->GetPopupNotifications(); - for (auto* notification : notifications) { - if (notification->id() == notification_id) - return true; - } - return false; - }; - - BeginScroll(); - ScrollBy(-200); - EXPECT_FALSE(IsRemovedAfterIdle(notification_id)); - EXPECT_TRUE(shown_as_popup(notification_id)); - EXPECT_EQ(-200.f, GetNotificationSlideAmount()); - EndScroll(); - EXPECT_FALSE(IsRemovedAfterIdle(notification_id)); - EXPECT_FALSE(shown_as_popup(notification_id)); -} - -TEST_F(NotificationViewTest, Pinned) { - // Notifications are popups by default (can't be pinned). - notification()->set_pinned(true); - UpdateNotificationViews(); - EXPECT_TRUE(GetCloseButton()); - - notification_view()->SetIsNested(); - UpdateNotificationViews(); - EXPECT_FALSE(GetCloseButton()); -} - -#endif // defined(OS_CHROMEOS) - -} // namespace message_center diff --git a/chromium/ui/message_center/views/proportional_image_view.cc b/chromium/ui/message_center/views/proportional_image_view.cc index b0d0d3ce84a..5766c47f1c1 100644 --- a/chromium/ui/message_center/views/proportional_image_view.cc +++ b/chromium/ui/message_center/views/proportional_image_view.cc @@ -48,7 +48,7 @@ const char* ProportionalImageView::GetClassName() const { } gfx::Size ProportionalImageView::GetImageDrawingSize() { - if (!visible()) + if (!GetVisible()) return gfx::Size(); gfx::Size max_size = max_image_size_; diff --git a/chromium/ui/message_center/views/slide_out_controller.cc b/chromium/ui/message_center/views/slide_out_controller.cc index d9d975b1297..57977736fdc 100644 --- a/chromium/ui/message_center/views/slide_out_controller.cc +++ b/chromium/ui/message_center/views/slide_out_controller.cc @@ -15,6 +15,7 @@ namespace message_center { namespace { constexpr int kSwipeRestoreDurationMs = 150; constexpr int kSwipeOutTotalDurationMs = 150; +gfx::Tween::Type kSwipeTweenType = gfx::Tween::EASE_IN; } // anonymous namespace SlideOutController::SlideOutController(ui::EventTarget* target, @@ -132,9 +133,11 @@ void SlideOutController::RestoreVisualState() { gesture_amount_ = 0.f; break; case SwipeControlOpenState::OPEN_ON_RIGHT: + gesture_amount_ = -swipe_control_width_; transform.Translate(-swipe_control_width_, 0); break; case SwipeControlOpenState::OPEN_ON_LEFT: + gesture_amount_ = swipe_control_width_; transform.Translate(swipe_control_width_, 0); break; } @@ -169,6 +172,7 @@ void SlideOutController::SetTransformWithAnimationIfNecessary( if (layer->transform() != transform) { ui::ScopedLayerAnimationSettings settings(layer->GetAnimator()); settings.SetTransitionDuration(animation_duration); + settings.SetTweenType(kSwipeTweenType); settings.AddObserver(this); // An animation starts. OnImplicitAnimationsCompleted will be called just diff --git a/chromium/ui/message_center/views/slide_out_controller.h b/chromium/ui/message_center/views/slide_out_controller.h index ed10291b63c..6fad760f3bd 100644 --- a/chromium/ui/message_center/views/slide_out_controller.h +++ b/chromium/ui/message_center/views/slide_out_controller.h @@ -70,6 +70,10 @@ class MESSAGE_CENTER_EXPORT SlideOutController // Effective only when swipe control is enabled by EnableSwipeControl(). void CloseSwipeControl(); + // Slides the view out and closes it after the animation. The sign of + // |direction| indicates which way the slide occurs. + void SlideOutAndClose(int direction); + private: // Positions where the slided view stays after the touch released. enum class SwipeControlOpenState { CLOSED, OPEN_ON_LEFT, OPEN_ON_RIGHT }; @@ -80,10 +84,6 @@ class MESSAGE_CENTER_EXPORT SlideOutController // Decides which position the slide should go back after touch is released. void CaptureControlOpenState(); - // Slides the view out and closes it after the animation. The sign of - // |direction| indicates which way the slide occurs. - void SlideOutAndClose(int direction); - // Sets the opacity of the slide out layer if |update_opacity_| is true. void SetOpacityIfNecessary(float opacity); |