Commit 8a5e15a5 authored by Ahmed Mehfooz's avatar Ahmed Mehfooz Committed by Commit Bot

Reland: Implement pop in and out animations for stacked notification icons

This CL includes a fix for a heap use after free error that existed
in the previous submission.

Bug: 1025050
Change-Id: I4928100f7a2599beb17741ec5f0ab22774385c29
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/1931411
Commit-Queue: Ahmed Mehfooz <amehfooz@chromium.org>
Reviewed-by: default avatarXiyuan Xia <xiyuan@chromium.org>
Cr-Commit-Position: refs/heads/master@{#718768}
parent 66922ea9
...@@ -13,8 +13,11 @@ ...@@ -13,8 +13,11 @@
#include "ash/system/tray/tray_popup_utils.h" #include "ash/system/tray/tray_popup_utils.h"
#include "ash/system/unified/rounded_label_button.h" #include "ash/system/unified/rounded_label_button.h"
#include "ui/base/l10n/l10n_util.h" #include "ui/base/l10n/l10n_util.h"
#include "ui/compositor/layer_animation_sequence.h"
#include "ui/compositor/layer_animator.h"
#include "ui/compositor/scoped_layer_animation_settings.h" #include "ui/compositor/scoped_layer_animation_settings.h"
#include "ui/gfx/canvas.h" #include "ui/gfx/canvas.h"
#include "ui/gfx/interpolated_transform.h"
#include "ui/message_center/message_center.h" #include "ui/message_center/message_center.h"
#include "ui/message_center/public/cpp/message_center_constants.h" #include "ui/message_center/public/cpp/message_center_constants.h"
#include "ui/message_center/vector_icons.h" #include "ui/message_center/vector_icons.h"
...@@ -120,14 +123,115 @@ class StackingBarLabelButton : public views::LabelButton { ...@@ -120,14 +123,115 @@ class StackingBarLabelButton : public views::LabelButton {
} // namespace } // namespace
class StackedNotificationBar::StackedNotificationBarIcon class StackedNotificationBar::StackedNotificationBarIcon
: public views::ImageView { : public views::ImageView,
public ui::LayerAnimationObserver {
public: public:
StackedNotificationBarIcon(const std::string& id) StackedNotificationBarIcon(StackedNotificationBar* notification_bar,
: views::ImageView(), id_(id) {} const std::string& id)
: views::ImageView(), notification_bar_(notification_bar), id_(id) {
SetPaintToLayer();
layer()->SetFillsBoundsOpaquely(false);
}
~StackedNotificationBarIcon() override {
if (is_animating_out())
layer()->GetAnimator()->StopAnimating();
}
void AnimateIn() {
DCHECK(!is_animating_out());
std::unique_ptr<ui::InterpolatedTransform> scale =
std::make_unique<ui::InterpolatedScale>(
gfx::Point3F(kNotificationIconAnimationScaleFactor,
kNotificationIconAnimationScaleFactor, 1),
gfx::Point3F(1, 1, 1));
std::unique_ptr<ui::InterpolatedTransform> scale_about_pivot =
std::make_unique<ui::InterpolatedTransformAboutPivot>(
GetLocalBounds().CenterPoint(), std::move(scale));
scale_about_pivot->SetChild(std::make_unique<ui::InterpolatedTranslation>(
gfx::PointF(0, kNotificationIconAnimationLowPosition),
gfx::PointF(0, kNotificationIconAnimationHighPosition)));
std::unique_ptr<ui::LayerAnimationElement> scale_and_move_up =
ui::LayerAnimationElement::CreateInterpolatedTransformElement(
std::move(scale_about_pivot),
base::TimeDelta::FromMilliseconds(
kNotificationIconAnimationUpDurationMs));
scale_and_move_up->set_tween_type(gfx::Tween::EASE_IN);
std::unique_ptr<ui::LayerAnimationElement> move_down =
ui::LayerAnimationElement::CreateInterpolatedTransformElement(
std::make_unique<ui::InterpolatedTranslation>(
gfx::PointF(0, kNotificationIconAnimationHighPosition),
gfx::PointF(0, 0)),
base::TimeDelta::FromMilliseconds(
kNotificationIconAnimationDownDurationMs));
std::unique_ptr<ui::LayerAnimationSequence> sequence =
std::make_unique<ui::LayerAnimationSequence>();
sequence->AddElement(std::move(scale_and_move_up));
sequence->AddElement(std::move(move_down));
layer()->GetAnimator()->StartAnimation(sequence.release());
}
void AnimateOut() {
layer()->GetAnimator()->StopAnimating();
std::unique_ptr<ui::InterpolatedTransform> scale =
std::make_unique<ui::InterpolatedScale>(
gfx::Point3F(1, 1, 1),
gfx::Point3F(kNotificationIconAnimationScaleFactor,
kNotificationIconAnimationScaleFactor, 1));
std::unique_ptr<ui::InterpolatedTransform> scale_about_pivot =
std::make_unique<ui::InterpolatedTransformAboutPivot>(
gfx::Point(bounds().width() * 0.5, bounds().height() * 0.5),
std::move(scale));
scale_about_pivot->SetChild(std::make_unique<ui::InterpolatedTranslation>(
gfx::PointF(0, 0),
gfx::PointF(0, kNotificationIconAnimationLowPosition)));
std::unique_ptr<ui::LayerAnimationElement> scale_and_move_down =
ui::LayerAnimationElement::CreateInterpolatedTransformElement(
std::move(scale_about_pivot),
base::TimeDelta::FromMilliseconds(
kNotificationIconAnimationOutDurationMs));
scale_and_move_down->set_tween_type(gfx::Tween::EASE_IN);
std::unique_ptr<ui::LayerAnimationSequence> sequence =
std::make_unique<ui::LayerAnimationSequence>();
sequence->AddElement(std::move(scale_and_move_down));
sequence->AddObserver(this);
set_animating_out(true);
layer()->GetAnimator()->StartAnimation(sequence.release());
// Note |this| may be deleted after this point.
}
// ui::LayerAnimationObserver:
void OnLayerAnimationEnded(ui::LayerAnimationSequence* sequence) override {
set_animating_out(false);
notification_bar_->OnIconAnimatedOut(this);
// Note |this| is deleted after this point.
}
void OnLayerAnimationAborted(ui::LayerAnimationSequence* sequence) override {}
void OnLayerAnimationScheduled(
ui::LayerAnimationSequence* sequence) override {}
const std::string& id() const { return id_; } const std::string& id() const { return id_; }
bool is_animating_out() const { return animating_out_; }
void set_animating_out(bool animating_out) { animating_out_ = animating_out; }
private: private:
StackedNotificationBar* notification_bar_;
std::string id_; std::string id_;
bool animating_out_ = false;
}; };
StackedNotificationBar::StackedNotificationBar( StackedNotificationBar::StackedNotificationBar(
...@@ -238,7 +342,7 @@ void StackedNotificationBar::AddNotificationIcon( ...@@ -238,7 +342,7 @@ void StackedNotificationBar::AddNotificationIcon(
message_center::Notification* notification, message_center::Notification* notification,
bool at_front) { bool at_front) {
views::ImageView* icon_view_ = views::ImageView* icon_view_ =
new StackedNotificationBarIcon(notification->id()); new StackedNotificationBarIcon(this, notification->id());
if (at_front) if (at_front)
notification_icons_container_->AddChildViewAt(icon_view_, 0); notification_icons_container_->AddChildViewAt(icon_view_, 0);
else else
...@@ -257,8 +361,26 @@ void StackedNotificationBar::AddNotificationIcon( ...@@ -257,8 +361,26 @@ void StackedNotificationBar::AddNotificationIcon(
} }
} }
void StackedNotificationBar::OnIconAnimatedOut(views::View* icon) {
delete icon;
Layout();
}
StackedNotificationBar::StackedNotificationBarIcon*
StackedNotificationBar::GetFrontIcon() {
const auto i = std::find_if(
notification_icons_container_->children().cbegin(),
notification_icons_container_->children().cend(), [](const auto* v) {
return !static_cast<const StackedNotificationBarIcon*>(v)
->is_animating_out();
});
return (i == notification_icons_container_->children().cend()
? nullptr
: static_cast<StackedNotificationBarIcon*>(*i));
}
const StackedNotificationBar::StackedNotificationBarIcon* const StackedNotificationBar::StackedNotificationBarIcon*
StackedNotificationBar::GetIconFromId(const std::string& id) { StackedNotificationBar::GetIconFromId(const std::string& id) const {
for (auto* v : notification_icons_container_->children()) { for (auto* v : notification_icons_container_->children()) {
const StackedNotificationBarIcon* icon = const StackedNotificationBarIcon* icon =
static_cast<const StackedNotificationBarIcon*>(v); static_cast<const StackedNotificationBarIcon*>(v);
...@@ -276,10 +398,20 @@ void StackedNotificationBar::ShiftIconsLeft( ...@@ -276,10 +398,20 @@ void StackedNotificationBar::ShiftIconsLeft(
kStackedNotificationBarMaxIcons); kStackedNotificationBarMaxIcons);
// Remove required number of icons from the front. // Remove required number of icons from the front.
for (int i = 0; i < removed_icons_count; i++) { // Only animate if we're removing one icon.
delete notification_icons_container_->children().front(); if (removed_icons_count == 1) {
StackedNotificationBarIcon* icon = GetFrontIcon();
if (icon) {
icon->AnimateOut();
}
} else {
for (int i = 0; i < removed_icons_count; i++) {
StackedNotificationBarIcon* icon = GetFrontIcon();
if (icon) {
delete icon;
}
}
} }
// Add icons to the back if there was a backfill. // Add icons to the back if there was a backfill.
int backfill_start = kStackedNotificationBarMaxIcons - removed_icons_count; int backfill_start = kStackedNotificationBarMaxIcons - removed_icons_count;
int backfill_end = int backfill_end =
...@@ -306,6 +438,10 @@ void StackedNotificationBar::ShiftIconsRight( ...@@ -306,6 +438,10 @@ void StackedNotificationBar::ShiftIconsRight(
true /*at_front*/); true /*at_front*/);
++stacked_notification_count_; ++stacked_notification_count_;
} }
// Animate in the first stacked notification icon.
StackedNotificationBarIcon* icon = GetFrontIcon();
if (icon)
GetFrontIcon()->AnimateIn();
} }
void StackedNotificationBar::UpdateStackedNotifications( void StackedNotificationBar::UpdateStackedNotifications(
......
...@@ -9,6 +9,7 @@ ...@@ -9,6 +9,7 @@
#include "ash/system/message_center/message_center_scroll_bar.h" #include "ash/system/message_center/message_center_scroll_bar.h"
#include "ash/system/message_center/unified_message_center_view.h" #include "ash/system/message_center/unified_message_center_view.h"
#include "ash/system/message_center/unified_message_list_view.h" #include "ash/system/message_center/unified_message_list_view.h"
#include "ui/compositor/layer_animation_observer.h"
#include "ui/gfx/animation/animation_delegate.h" #include "ui/gfx/animation/animation_delegate.h"
#include "ui/message_center/message_center_observer.h" #include "ui/message_center/message_center_observer.h"
#include "ui/views/background.h" #include "ui/views/background.h"
...@@ -50,6 +51,9 @@ class StackedNotificationBar : public views::View, ...@@ -50,6 +51,9 @@ class StackedNotificationBar : public views::View,
// Set notification bar state to expanded. // Set notification bar state to expanded.
void SetExpanded(); void SetExpanded();
// Clean up icon view after it's removal animation is complete.
void OnIconAnimatedOut(views::View* icon);
// views::View: // views::View:
void OnPaint(gfx::Canvas* canvas) override; void OnPaint(gfx::Canvas* canvas) override;
const char* GetClassName() const override; const char* GetClassName() const override;
...@@ -66,9 +70,12 @@ class StackedNotificationBar : public views::View, ...@@ -66,9 +70,12 @@ class StackedNotificationBar : public views::View,
class StackedNotificationBarIcon; class StackedNotificationBarIcon;
friend class UnifiedMessageCenterViewTest; friend class UnifiedMessageCenterViewTest;
// Get the first icon which is not animating out.
StackedNotificationBarIcon* GetFrontIcon();
// Search for a icon view in the stacked notification bar based on a provided // Search for a icon view in the stacked notification bar based on a provided
// notification id. // notification id.
const StackedNotificationBarIcon* GetIconFromId(const std::string& id); const StackedNotificationBarIcon* GetIconFromId(const std::string& id) const;
// Set visibility based on number of stacked notifications or animation state. // Set visibility based on number of stacked notifications or animation state.
void UpdateVisibility(); void UpdateVisibility();
......
...@@ -135,6 +135,12 @@ constexpr gfx::Insets kStackedNotificationIconsContainerPadding(1, 16, 0, 8); ...@@ -135,6 +135,12 @@ constexpr gfx::Insets kStackedNotificationIconsContainerPadding(1, 16, 0, 8);
constexpr int kStackedNotificationBarMaxIcons = 3; constexpr int kStackedNotificationBarMaxIcons = 3;
constexpr int kStackedNotificationBarIconSpacing = 6; constexpr int kStackedNotificationBarIconSpacing = 6;
constexpr int kStackedNotificationIconSize = 18; constexpr int kStackedNotificationIconSize = 18;
constexpr int kNotificationIconAnimationLowPosition = 7;
constexpr int kNotificationIconAnimationHighPosition = -3;
constexpr double kNotificationIconAnimationScaleFactor = 0.77;
constexpr int kNotificationIconAnimationUpDurationMs = 50;
constexpr int kNotificationIconAnimationDownDurationMs = 17;
constexpr int kNotificationIconAnimationOutDurationMs = 67;
// Constants used in FeaturePodsView of UnifiedSystemTray. // Constants used in FeaturePodsView of UnifiedSystemTray.
constexpr gfx::Size kUnifiedFeaturePodIconSize(48, 48); constexpr gfx::Size kUnifiedFeaturePodIconSize(48, 48);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment