Implement AssistantProgressIndicator motion spec.
Still missing tweens. Need to discuss with UX about potentially revising
specs to use pre-defined tweens.
See bug for demo.
Bug: b:111573788
Change-Id: I7d94416afa834d83aafa7e1e5f8eb9d6efe44333
Reviewed-on: https://chromium-review.googlesource.com/1144197
Commit-Queue: David Black <dmblack@google.com>
Reviewed-by: Xiaohui Chen <xiaohuic@chromium.org>
Cr-Commit-Position: refs/heads/master@{#577765}
diff --git a/ash/assistant/ui/dialog_plate/dialog_plate.cc b/ash/assistant/ui/dialog_plate/dialog_plate.cc
index 667af5fa..ef82ec08b 100644
--- a/ash/assistant/ui/dialog_plate/dialog_plate.cc
+++ b/ash/assistant/ui/dialog_plate/dialog_plate.cc
@@ -36,6 +36,8 @@
constexpr int kPreferredHeightDip = 48;
// Animation.
+constexpr base::TimeDelta kAnimationFadeInDelay =
+ base::TimeDelta::FromMilliseconds(83);
constexpr base::TimeDelta kAnimationFadeInDuration =
base::TimeDelta::FromMilliseconds(100);
constexpr base::TimeDelta kAnimationFadeOutDuration =
@@ -258,11 +260,13 @@
gfx::Transform(), kAnimationTransformInDuration,
gfx::Tween::Type::FAST_OUT_SLOW_IN_2)),
// Animate opacity to 100% with delay.
- assistant::util::CreateLayerAnimationSequenceWithDelay(
+ assistant::util::CreateLayerAnimationSequence(
+ ui::LayerAnimationElement::CreatePauseElement(
+ ui::LayerAnimationElement::AnimatableProperty::OPACITY,
+ kAnimationFadeInDelay),
assistant::util::CreateOpacityElement(
1.f, kAnimationFadeInDuration,
- gfx::Tween::Type::FAST_OUT_LINEAR_IN),
- /*delay=*/kAnimationFadeOutDuration)});
+ gfx::Tween::Type::FAST_OUT_LINEAR_IN))});
// When switching to keyboard input modality, we focus the textfield.
textfield_->RequestFocus();
@@ -290,11 +294,13 @@
gfx::Transform(), kAnimationTransformInDuration,
gfx::Tween::Type::FAST_OUT_SLOW_IN_2)),
// Animate opacity to 100% with delay.
- assistant::util::CreateLayerAnimationSequenceWithDelay(
+ assistant::util::CreateLayerAnimationSequence(
+ ui::LayerAnimationElement::CreatePauseElement(
+ ui::LayerAnimationElement::AnimatableProperty::OPACITY,
+ kAnimationFadeInDelay),
assistant::util::CreateOpacityElement(
1.f, kAnimationFadeInDuration,
- gfx::Tween::Type::FAST_OUT_LINEAR_IN),
- /*delay=*/kAnimationFadeOutDuration)});
+ gfx::Tween::Type::FAST_OUT_LINEAR_IN))});
break;
}
case InputModality::kStylus:
diff --git a/ash/assistant/ui/main_stage/assistant_progress_indicator.cc b/ash/assistant/ui/main_stage/assistant_progress_indicator.cc
index d7d1ceb..6eff37731 100644
--- a/ash/assistant/ui/main_stage/assistant_progress_indicator.cc
+++ b/ash/assistant/ui/main_stage/assistant_progress_indicator.cc
@@ -4,47 +4,61 @@
#include "ash/assistant/ui/main_stage/assistant_progress_indicator.h"
-#include <memory>
-
+#include "ash/assistant/util/animation_util.h"
+#include "base/bind.h"
+#include "base/time/time.h"
+#include "ui/compositor/layer_animation_element.h"
+#include "ui/compositor/layer_animator.h"
#include "ui/gfx/canvas.h"
#include "ui/gfx/color_palette.h"
+#include "ui/views/background.h"
#include "ui/views/layout/box_layout.h"
namespace ash {
namespace {
+// Appearance.
constexpr int kDotCount = 3;
-constexpr int kDotSizeDip = 6;
+constexpr float kDotLargeSizeDip = 9.f;
+constexpr float kDotSmallSizeDip = 6.f;
constexpr int kSpacingDip = 4;
-// DotView ---------------------------------------------------------------------
+// Animation.
+constexpr base::TimeDelta kAnimationOffsetDuration =
+ base::TimeDelta::FromMilliseconds(216);
+constexpr base::TimeDelta kAnimationPauseDuration =
+ base::TimeDelta::FromMilliseconds(500);
+constexpr base::TimeDelta kAnimationScaleUpDuration =
+ base::TimeDelta::FromMilliseconds(266);
+constexpr base::TimeDelta kAnimationScaleDownDuration =
+ base::TimeDelta::FromMilliseconds(450);
-class DotView : public views::View {
+// Transformation.
+constexpr float kScaleFactor = kDotLargeSizeDip / kDotSmallSizeDip;
+constexpr float kTranslationDip = -(kDotLargeSizeDip - kDotSmallSizeDip) / 2.f;
+
+// DotBackground ---------------------------------------------------------------
+
+class DotBackground : public views::Background {
public:
- DotView() = default;
- ~DotView() override = default;
+ DotBackground() = default;
+ ~DotBackground() override = default;
- // views::View:
- gfx::Size CalculatePreferredSize() const override {
- return gfx::Size(kDotSizeDip, GetHeightForWidth(kDotSizeDip));
- }
-
- int GetHeightForWidth(int width) const override { return kDotSizeDip; }
-
- void OnPaint(gfx::Canvas* canvas) override {
+ void Paint(gfx::Canvas* canvas, views::View* view) const override {
cc::PaintFlags flags;
flags.setAntiAlias(true);
flags.setColor(gfx::kGoogleGrey300);
- const gfx::Rect& b = GetContentsBounds();
+ const gfx::Rect& b = view->GetContentsBounds();
const gfx::Point center = gfx::Point(b.width() / 2, b.height() / 2);
+ const int radius = std::min(b.width() / 2, b.height() / 2);
- canvas->DrawCircle(center, kDotSizeDip / 2, flags);
+ canvas->DrawCircle(center, radius, flags);
}
private:
- DISALLOW_COPY_AND_ASSIGN(DotView);
+ DISALLOW_COPY_AND_ASSIGN(DotBackground);
};
} // namespace
@@ -61,9 +75,72 @@
SetLayoutManager(std::make_unique<views::BoxLayout>(
views::BoxLayout::Orientation::kHorizontal, gfx::Insets(), kSpacingDip));
- // Dots.
- for (int i = 0; i < kDotCount; ++i)
- AddChildView(new DotView());
+ // Initialize dots.
+ for (int i = 0; i < kDotCount; ++i) {
+ views::View* dot_view = new views::View();
+ dot_view->SetBackground(std::make_unique<DotBackground>());
+ dot_view->SetPreferredSize(gfx::Size(kDotSmallSizeDip, kDotSmallSizeDip));
+
+ // Dots will animate on their own layers.
+ dot_view->SetPaintToLayer();
+ dot_view->layer()->SetFillsBoundsOpaquely(false);
+
+ AddChildView(dot_view);
+ }
+}
+
+void AssistantProgressIndicator::AddedToWidget() {
+ VisibilityChanged(/*starting_from=*/this, /*is_visible=*/visible());
+}
+
+void AssistantProgressIndicator::RemovedFromWidget() {
+ VisibilityChanged(/*starting_from=*/this, /*is_visible=*/false);
+}
+
+void AssistantProgressIndicator::VisibilityChanged(views::View* starting_from,
+ bool is_visible) {
+ if (!is_visible) {
+ // Stop all animations.
+ for (int i = 0; i < child_count(); ++i) {
+ child_at(i)->layer()->GetAnimator()->StopAnimating();
+ }
+ return;
+ }
+
+ using namespace assistant::util;
+
+ // The animation performs scaling on the child views. In order to give the
+ // illusion that scaling is being performed about the center of the view as
+ // the transformation origin, we also need to perform a translation.
+ gfx::Transform transform;
+ transform.Translate(kTranslationDip, kTranslationDip);
+ transform.Scale(kScaleFactor, kScaleFactor);
+
+ for (int i = 0; i < child_count(); ++i) {
+ views::View* view = child_at(i);
+
+ if (i > 0) {
+ // Schedule the animations to start after an offset.
+ view->layer()->GetAnimator()->SchedulePauseForProperties(
+ i * kAnimationOffsetDuration,
+ ui::LayerAnimationElement::AnimatableProperty::TRANSFORM);
+ }
+
+ // Schedule transformation animation.
+ view->layer()->GetAnimator()->ScheduleAnimation(
+ CreateLayerAnimationSequence(
+ // Animate scale up.
+ CreateTransformElement(transform, kAnimationScaleUpDuration),
+ // Animate scale down.
+ CreateTransformElement(gfx::Transform(),
+ kAnimationScaleDownDuration),
+ // Pause before next iteration.
+ ui::LayerAnimationElement::CreatePauseElement(
+ ui::LayerAnimationElement::AnimatableProperty::TRANSFORM,
+ kAnimationPauseDuration),
+ // Animation parameters.
+ {.is_cyclic = true}));
+ }
}
} // namespace ash
\ No newline at end of file
diff --git a/ash/assistant/ui/main_stage/assistant_progress_indicator.h b/ash/assistant/ui/main_stage/assistant_progress_indicator.h
index 43496d1..0dd8f74 100644
--- a/ash/assistant/ui/main_stage/assistant_progress_indicator.h
+++ b/ash/assistant/ui/main_stage/assistant_progress_indicator.h
@@ -5,6 +5,8 @@
#ifndef ASH_ASSISTANT_UI_MAIN_STAGE_ASSISTANT_PROGRESS_INDICATOR_H_
#define ASH_ASSISTANT_UI_MAIN_STAGE_ASSISTANT_PROGRESS_INDICATOR_H_
+#include <memory>
+
#include "base/macros.h"
#include "ui/views/view.h"
@@ -15,6 +17,11 @@
AssistantProgressIndicator();
~AssistantProgressIndicator() override;
+ // views::View:
+ void AddedToWidget() override;
+ void RemovedFromWidget() override;
+ void VisibilityChanged(views::View* starting_from, bool is_visible) override;
+
private:
void InitLayout();
diff --git a/ash/assistant/util/animation_util.cc b/ash/assistant/util/animation_util.cc
index acc7519..dbc90f7 100644
--- a/ash/assistant/util/animation_util.cc
+++ b/ash/assistant/util/animation_util.cc
@@ -14,7 +14,34 @@
ui::LayerAnimationSequence* CreateLayerAnimationSequence(
std::unique_ptr<ui::LayerAnimationElement> a,
- std::unique_ptr<ui::LayerAnimationElement> b) {
+ const LayerAnimationSequenceParams& params) {
+ return CreateLayerAnimationSequence(std::move(a), nullptr, nullptr, nullptr,
+ params);
+}
+
+ui::LayerAnimationSequence* CreateLayerAnimationSequence(
+ std::unique_ptr<ui::LayerAnimationElement> a,
+ std::unique_ptr<ui::LayerAnimationElement> b,
+ const LayerAnimationSequenceParams& params) {
+ return CreateLayerAnimationSequence(std::move(a), std::move(b), nullptr,
+ nullptr, params);
+}
+
+ui::LayerAnimationSequence* CreateLayerAnimationSequence(
+ std::unique_ptr<ui::LayerAnimationElement> a,
+ std::unique_ptr<ui::LayerAnimationElement> b,
+ std::unique_ptr<ui::LayerAnimationElement> c,
+ const LayerAnimationSequenceParams& params) {
+ return CreateLayerAnimationSequence(std::move(a), std::move(b), std::move(c),
+ nullptr, params);
+}
+
+ui::LayerAnimationSequence* CreateLayerAnimationSequence(
+ std::unique_ptr<ui::LayerAnimationElement> a,
+ std::unique_ptr<ui::LayerAnimationElement> b,
+ std::unique_ptr<ui::LayerAnimationElement> c,
+ std::unique_ptr<ui::LayerAnimationElement> d,
+ const LayerAnimationSequenceParams& params) {
ui::LayerAnimationSequence* layer_animation_sequence =
new ui::LayerAnimationSequence();
@@ -23,24 +50,13 @@
if (b)
layer_animation_sequence->AddElement(std::move(b));
- return layer_animation_sequence;
-}
+ if (c)
+ layer_animation_sequence->AddElement(std::move(c));
-ui::LayerAnimationSequence* CreateLayerAnimationSequenceWithDelay(
- std::unique_ptr<ui::LayerAnimationElement> layer_animation_element,
- const base::TimeDelta& delay) {
- DCHECK(delay.InMilliseconds() >= 0);
+ if (d)
+ layer_animation_sequence->AddElement(std::move(d));
- ui::LayerAnimationSequence* layer_animation_sequence =
- new ui::LayerAnimationSequence();
-
- if (!delay.is_zero()) {
- layer_animation_sequence->AddElement(
- ui::LayerAnimationElement::CreatePauseElement(
- layer_animation_element->properties(), delay));
- }
-
- layer_animation_sequence->AddElement(std::move(layer_animation_element));
+ layer_animation_sequence->set_is_cyclic(params.is_cyclic);
return layer_animation_sequence;
}
diff --git a/ash/assistant/util/animation_util.h b/ash/assistant/util/animation_util.h
index 5d55e23..8b0c65c 100644
--- a/ash/assistant/util/animation_util.h
+++ b/ash/assistant/util/animation_util.h
@@ -22,19 +22,45 @@
namespace assistant {
namespace util {
-// Creates a LayerAnimationSequence containing the specified
-// LayerAnimationElements. The method caller assumes ownership of the
-// returned pointer.
-ui::LayerAnimationSequence* CreateLayerAnimationSequence(
- std::unique_ptr<ui::LayerAnimationElement> a,
- std::unique_ptr<ui::LayerAnimationElement> b = nullptr);
+// Parameters for a LayerAnimationSequence.
+struct LayerAnimationSequenceParams {
+ // True if the animation sequence should loop endlessly, false otherwise.
+ bool is_cyclic = false;
+};
// Creates a LayerAnimationSequence containing the specified
-// |layer_animation_element| to be started after the given |delay|. The method
-// caller assumes ownership of the returned pointer.
-ui::LayerAnimationSequence* CreateLayerAnimationSequenceWithDelay(
- std::unique_ptr<ui::LayerAnimationElement> layer_animation_element,
- const base::TimeDelta& delay);
+// LayerAnimationElements with the given |params|. The method caller assumes
+// ownership of the returned pointer.
+ui::LayerAnimationSequence* CreateLayerAnimationSequence(
+ std::unique_ptr<ui::LayerAnimationElement> a,
+ const LayerAnimationSequenceParams& params = {});
+
+// Creates a LayerAnimationSequence containing the specified
+// LayerAnimationElements with the given |params|. The method caller assumes
+// ownership of the returned pointer.
+ui::LayerAnimationSequence* CreateLayerAnimationSequence(
+ std::unique_ptr<ui::LayerAnimationElement> a,
+ std::unique_ptr<ui::LayerAnimationElement> b,
+ const LayerAnimationSequenceParams& params = {});
+
+// Creates a LayerAnimationSequence containing the specified
+// LayerAnimationElements with the given |params|. The method caller assumes
+// ownership of the returned pointer.
+ui::LayerAnimationSequence* CreateLayerAnimationSequence(
+ std::unique_ptr<ui::LayerAnimationElement> a,
+ std::unique_ptr<ui::LayerAnimationElement> b,
+ std::unique_ptr<ui::LayerAnimationElement> c,
+ const LayerAnimationSequenceParams& params = {});
+
+// Creates a LayerAnimationSequence containing the specified
+// LayerAnimationElements with the given |params|. The method caller assumes
+// ownership of the returned pointer.
+ui::LayerAnimationSequence* CreateLayerAnimationSequence(
+ std::unique_ptr<ui::LayerAnimationElement> a,
+ std::unique_ptr<ui::LayerAnimationElement> b,
+ std::unique_ptr<ui::LayerAnimationElement> c,
+ std::unique_ptr<ui::LayerAnimationElement> d,
+ const LayerAnimationSequenceParams& params = {});
// Creates a LayerAnimationElement to animate opacity with the given parameters.
std::unique_ptr<ui::LayerAnimationElement> CreateOpacityElement(