Commit 7f1d7d43 authored by David Black's avatar David Black Committed by Commit Bot

Adds entry/exit animations for in-Assistant notifications.

Per UX requirements, in-Assistant notifications should be animated in
and out smoothly.

Demo:
https://drive.google.com/open?id=1KPaOCen6pmHFV8_SRV1w5hqYNDBN2xsJ

Bug: b:118654460
Change-Id: Ie02827f8a0d864cd2f652b668b9880bcd51246df
Reviewed-on: https://chromium-review.googlesource.com/c/1483708
Commit-Queue: David Black <dmblack@google.com>
Reviewed-by: default avatarXiaohui Chen <xiaohuic@chromium.org>
Cr-Commit-Position: refs/heads/master@{#636138}
parent 47d82df7
......@@ -9,6 +9,7 @@
#include "ash/assistant/ui/main_stage/suggestion_chip_view.h"
#include "base/strings/utf_string_conversions.h"
#include "chromeos/services/assistant/public/mojom/assistant.mojom.h"
#include "ui/compositor/scoped_layer_animation_settings.h"
#include "ui/views/animation/ink_drop_painted_layer_delegates.h"
#include "ui/views/controls/button/button.h"
#include "ui/views/controls/label.h"
......@@ -26,6 +27,10 @@ constexpr int kPaddingRightDip = 8;
constexpr int kPreferredHeightDip = 48;
constexpr int kShadowElevationDip = 6;
// Animation.
constexpr base::TimeDelta kAnimationDuration =
base::TimeDelta::FromMilliseconds(250);
// Helpers ---------------------------------------------------------------------
views::View* CreateButton(
......@@ -56,6 +61,10 @@ const char* AssistantNotificationView::GetClassName() const {
return "AssistantNotificationView";
}
void AssistantNotificationView::AddedToWidget() {
UpdateVisibility(/*visible=*/true);
}
gfx::Size AssistantNotificationView::CalculatePreferredSize() const {
return gfx::Size(INT_MAX, GetHeightForWidth(INT_MAX));
}
......@@ -77,6 +86,14 @@ void AssistantNotificationView::ButtonPressed(views::Button* sender,
notification_button_index);
}
void AssistantNotificationView::OnImplicitAnimationsCompleted() {
// When the view's layer has animated to |0.f| opacity, the underlying
// notification has been removed and our associated view can be deleted. Note
// that we check for opacity within epsilon to avoid exact float comparison.
if (cc::MathUtil::IsWithinEpsilon(layer()->opacity(), 0.f))
delete this;
}
void AssistantNotificationView::OnNotificationUpdated(
const AssistantNotification* notification) {
// We only care about the |notification| being updated if it is the
......@@ -90,7 +107,7 @@ void AssistantNotificationView::OnNotificationUpdated(
// If the notification associated with this view is no longer of type
// |kInAssistant|, it should not be shown in Assistant UI.
if (notification->type != AssistantNotificationType::kInAssistant) {
delete this;
UpdateVisibility(/*visible=*/false);
return;
}
......@@ -120,7 +137,7 @@ void AssistantNotificationView::OnNotificationRemoved(
const AssistantNotification* notification,
bool from_server) {
if (notification->client_id == notification_id_)
delete this;
UpdateVisibility(/*visible=*/false);
}
void AssistantNotificationView::InitLayout(
......@@ -130,6 +147,10 @@ void AssistantNotificationView::InitLayout(
SetPaintToLayer();
layer()->SetFillsBoundsOpaquely(false);
// Initialize opacity to |0.f| as the layer for this view will be animated in
// when the view is added to its widget.
layer()->SetOpacity(0.f);
// Background/shadow.
background_layer_.SetFillsBoundsOpaquely(false);
layer()->Add(&background_layer_);
......@@ -194,4 +215,22 @@ void AssistantNotificationView::UpdateBackground() {
gfx::ToEnclosingRect(shadow_delegate_->GetPaintedBounds()));
}
void AssistantNotificationView::UpdateVisibility(bool visible) {
ui::ScopedLayerAnimationSettings animation(layer()->GetAnimator());
// We observe the animation to receive an event on its completion. When the
// layer for this view has completed animating to a hidden state, this view
// is deleted as the underlying notification has been removed.
animation.AddObserver(this);
// Parameters.
animation.SetPreemptionStrategy(
ui::LayerAnimator::PreemptionStrategy::IMMEDIATELY_ANIMATE_TO_NEW_TARGET);
animation.SetTransitionDuration(kAnimationDuration);
animation.SetTweenType(gfx::Tween::Type::EASE_IN_OUT);
// Animate opacity to a visible/hidden state.
layer()->SetOpacity(visible ? 1.f : 0.f);
}
} // namespace ash
......@@ -13,6 +13,7 @@
#include "base/component_export.h"
#include "base/macros.h"
#include "ui/compositor/layer.h"
#include "ui/compositor/layer_animation_observer.h"
#include "ui/views/controls/button/button.h"
#include "ui/views/view.h"
......@@ -30,6 +31,7 @@ class AssistantViewDelegate;
class COMPONENT_EXPORT(ASSISTANT_UI) AssistantNotificationView
: public views::View,
public views::ButtonListener,
public ui::ImplicitAnimationObserver,
public AssistantNotificationModelObserver {
public:
AssistantNotificationView(AssistantViewDelegate* delegate,
......@@ -38,13 +40,17 @@ class COMPONENT_EXPORT(ASSISTANT_UI) AssistantNotificationView
// views::View:
const char* GetClassName() const override;
void AddedToWidget() override;
gfx::Size CalculatePreferredSize() const override;
int GetHeightForWidth(int width) const override;
void OnBoundsChanged(const gfx::Rect& previous_bounds) override;
// views::Button:
// views::ButtonListener:
void ButtonPressed(views::Button* sender, const ui::Event& event) override;
// ui::ImplicitAnimationObserver:
void OnImplicitAnimationsCompleted() override;
// AssistantNotificationModelObserver:
void OnNotificationUpdated(
const AssistantNotification* notification) override;
......@@ -54,6 +60,7 @@ class COMPONENT_EXPORT(ASSISTANT_UI) AssistantNotificationView
private:
void InitLayout(const AssistantNotification* notification);
void UpdateBackground();
void UpdateVisibility(bool visible);
AssistantViewDelegate* const delegate_; // Owned by AssistantController.
const std::string notification_id_;
......
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